# `@scaleway/use-i18n`

## A tiny hooks to handle i18n translation

## Install

```bash
pnpm add @scaleway/use-i18n
```

## Usage

### Loading locales

Create a directory with your locales.
Use of local `variables` and `namespace` to dynamically load locales.

**Exemple :**

```text
📦locales
 ┣ 📂de
 ┃ ┗ 📜common.json
 ┣ 📂en
 ┃ ┗ 📜common.json
 ┗ 📂fr
 ┃ ┗ 📜common.json
```

your loaders will be:

```js
const load = ({ locale, namespace }) => import(`./locales/${locale}/${namespace}`)
const loadDateLocale = locale => import(`date-fns/locale/${locale}/index`)
```

Inside your app you will need to use useTranslation to load namespace locales.

if you want to have pre-load locales you can use defaultTranslations.

```js
import I18n from '@scaleway/use-i18n'
import defaultTranslations from './locales/en/common'

const App = () => (
  <I18n
    loadDateLocale={loadDateLocale}
    defaultLocale="en"
    supportedLocales={['en']}
    defaultTranslations={defaultTranslations}
  >
    <App />
  </I18n>
)
```

```js
import React from 'react'
import I18n from '@scaleway/use-i18n'

const Page = () => {
  // this will load locales based on `./locales/${currentLocale}/common.json`
  const { t } = useTranlation(['common'])

  return <h1>{t('title')}</h1>
}

const App = () => {
  const defaultLocales = ['fr', 'en']
  const defaultTranslations = {
    title: 'Welcome to I18n hooks',
  }

  const load = ({ locale, namespace }) => import(`./locales/${locale}/${namespace}`)

  return (
    <I18n defaultLocale="en" supportedLocales={defaultLocales} defaultTranslations={defaultTranslations}>
      <Page />
    </I18n>
  )
}
```

### useTranslation & useI18n

Theses both hooks are using the same context.
useTranslation will load your locales with a use effect.
Dynamique locale need to be loaded before using useI18n on an other file.

```js
import { useTranslation } from '@scaleway/use-i18n'

const App = () => {
  const i18n = useTranslation(['app', 'common'])

  return <>{i18n.t('app.user')}(</>
}
```

In a case you will need to avoid somes useless re-render. you can wait that all your namespaces are loaded

```js
import { useTranslation } from '@scaleway/use-i18n'

const App = () => {
  const namespaces = ['app', 'common']
  const { t, isLoaded } = useTranslation(namespaces)

  return isLoaded ? <>{t('app.user')}(</> : null
}
```

```js
import { useI18n } from '@scaleway/use-i18n'

const { namespaceTranslation } = useI18n()
const t = namespaceTranslation('namespace.home.users.table.header')
```

### use namespaceTranslation

Namespace translation help you when you have some very long key
Exemple of your locale key: `namespace.home.users.table.header.link`

```js
import { useI18n } from '@scaleway/use-i18n'

const { namespaceTranslation } = useI18n()
const t = namespaceTranslation('namespace.home.users.table.header')
```

### use locales from date-fns

You will need sometimes to give locales to somes compoent
In this example, we will use react-date-picker.js

```js
import { useI18n } from '@scaleway/use-i18n'
import { DateInput } from '@scaleway/ui'

const App = () => {
  const { t, currentLocale, dateFnsLocale } = useI18n()

  return (
    <div>
      <DateInput
        currentLocale={currentLocale}
        locale={dateFnsLocale}
        label={t('form.fields.date.label')}
        placeholder={t('form.fields.date.placeholder')}
      />
    </div>
  )
}
```

### formatDate

This hook exposes a `formatDate` function which can be used to format JS dates

The first parameter is anything that can be accepted as a valid JS Date (Date, number, string)

It accepts an `options` as second parameter which can eiter be one of predefined shorthand formats (see below) or an [Intl.DateTimeFormat `options` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat)

Shorthand formats:

```text
"long" => "February 13, 2020"
"short" => (default) "Feb 13, 2020"
"hour" => "February 13, 2020, 4:28 PM"
"hourOnly" => "4:28 PM"
"shortWithoutDay" => "Feb 2020"
"numeric" => "2020-02-13"
"numericHour" => "2020-02-13 4:28 PM"
```

```js
import { useI18n } from '@scaleway/use-i18n'

const App = () => {
  const { formatDate } = useI18n()

  const units = [
    formatDate(new Date(2020, 1, 13, 16, 28)), // "Feb 13, 2020"
    formatDate(1581607680000, 'long'), // "February 13, 2020"
    formatDate('2020-02-13T15:28:00.000Z', {
      day: 'numeric',
      era: 'short',
      hour: '2-digit',
      minute: 'numeric',
      month: 'narrow',
      second: '2-digit',
      timeZoneName: 'long',
      weekday: 'long',
      year: '2-digit',
    }), // "Thursday, F 13, 20 AD, 04:28:00 PM Central European Standard Time""
  ]

  return <div>{units}</div>
}
```

### formatList

This hook exposes a `formatList` function which can be used to format lists of strings.

The first parameter is an array of strings to format.

It accepts an `options` as second parameter which is an [Intl.ListFormat `options` object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat/ListFormat).

```js
import { useI18n } from '@scaleway/use-i18n'

const App = () => {
  const { formatList } = useI18n()

  const cities = [
    formatList(['Paris', 'New York', 'London']), // Paris, New York and London
    formatList(['Paris', 'New York', 'London'], {
      type: 'disjunction',
    }), // Paris, New York or London
  ]

  return <div>{cities}</div>
}
```

### formatUnit

This hook also exposes a `formatUnit` function which can be used to format bits/bytes until [ECMA-402 Unit Preferences](https://github.com/tc39/proposal-smart-unit-preferences) is standardised

We follow the IEC standard (base 10) with SI units (kilo,mega,giga,...) [more info here](https://en.wikipedia.org/wiki/Binary_prefix)

It accepts an `options` as second parameter:

- `unit`: Manadatory (see below)
- `maximumFractionDigits`: The maximum number of fraction digits to use
- `minimumFractionDigits`: The minimum number of fraction digits to use
- `short`: if it should output the short or long form of the unit (think `Kb` vs `kilobits`)

```js
import { useI18n } from '@scaleway/use-i18n'

const App = () => {
  const { formatUnit } = useI18n()

  const units = [
    formatUnit(12, { unit: 'kilobyte' }), // "12 KB" or "12 Ko" in fr an ro
    formatUnit(10 ** 8, { unit: 'bytes-humanized' }), // "100 MB" or "100 Mo" in fr an ro
    formatUnit(10 ** 8, { unit: 'bits-per-second-humanized' }), // "100Mbs"
  ]

  return <div>{units}</div>
}
```

We currently support two different unit:

- byte
- bit

With each some variants :

- `(kilo|mega|giga|tera|peta|exa|zetta|yotta)(bit|byte)`: This is the bare unit
  - `formatUnit(12, { unit: 'megabyte' })` => `"12 MB"` or `"12 Mo"` (in fr/ro)
  - `formatUnit(12, { unit: 'kilobit' })` => `"12 Kb"`
  - `formatUnit(12, { unit: 'gigabit' })` => `"12 Gb"`
  - `formatUnit(12, { unit: 'byte' })` => `"12 B"` or `"12 o"` (in fr/ro)
- `(byte|bit)s-humanized`: This is an automated unit which will print a human readable value
  - `formatUnit(1234567, { unit: 'bytes-humanized' })` => `"1.23 MB"` or `"1.23 Mo"` (in fr/ro)
- `(kilo|mega|giga|tera|peta|exa|zetta|yotta)(bit|byte)(byte|bit)-humanized`: This is also an automated unit which will print a human readable value but in the unit specified
  - `formatUnit(123456789, { unit: 'gigabyte-humanized' })` => `"0.12 GB"` or `"0.12 Go"` (in fr/ro)
  - `formatUnit(123456789, { unit: 'kilobyte-humanized' })` => `"123456.78 KB"` or `"123456.78 Ko"` (in fr/ro)

There is also a compound variant which can only be used with bits:

- `(kilo|mega|giga|tera|peta|exa|zetta|yotta)bit-per-second`
  - `formatUnit(1.6, { unit: 'gigabit-per-second' })` => `1.6 Gbps`
  - `formatUnit(1.6, { unit: 'bit-per-second' })` => `1.6 bps`
- `bits-per-second-humanized`: Automated unit
  - `formatUnit(123456789, { unit: 'bits-per-second-humanized' })` => `123.46 Mbps`
- `(kilo|mega|giga|tera|peta|exa|zetta|yotta)bit-per-second-humanized`: Humandreadable value in the unit specified
  - `formatUnit(123456789, { unit: 'gigabit-per-second-humanized' })` => `0.12 Gbps`
  - `formatUnit(123456789, { unit: 'kilobit-per-second-humanized' })` => `123456.78 Kbps`

Here is the full list of available units:

```text
bits-humanized
bits-per-second-humanized
bit
bit-per-second
bit-humanized
bit-per-second-humanized
kilobit
kilobit-per-second
kilobit-humanized
kilobit-per-second-humanized
megabit
megabit-per-second
megabit-humanized
megabit-per-second-humanized
gigabit
gigabit-per-second
gigabit-humanized
gigabit-per-second-humanized
terabit
terabit-per-second
terabit-humanized
terabit-per-second-humanized
petabit
petabit-per-second
petabit-humanized
petabit-per-second-humanized
exabit
exabit-per-second
exabit-humanized
exabit-per-second-humanized
zettabit
zettabit-per-second
zettabit-humanized
zettabit-per-second-humanized
yottabit
yottabit-per-second
yottabit-humanized
yottabit-per-second-humanized
bytes-humanized
byte
byte-humanized
kilobyte
kilobyte-humanized
megabyte
megabyte-humanized
gigabyte
gigabyte-humanized
terabyte
terabyte-humanized
petabyte
petabyte-humanized
exabyte
exabyte-humanized
zettabyte
zettabyte-humanized
yottabyte
yottabyte-humanized
```
