Skip to content

Commit

Permalink
feat(Forms): add Form.useTranslation hook (#4123)
Browse files Browse the repository at this point in the history
This PR relies on #4121 as of now.

This lets form components consume the internal translations as well as
extending the translations with your own strings:

```tsx
import { Form } from '@dnb/eufemia/extensions/forms'

const myTranslations = {
  'en-GB': {
    Custom: {
      translation: 'My translation with a {myKey}',
    },
  },
}

function MyComponent() {
  const { Custom, formatMessage } = Form.useTranslation<myTranslations>()

  // Use it directly
  const str1 = formatMessage(Custom.translation, {
    myKey: 'value!',
  })

  // Or use it with a key
  const str2 = formatMessage('Field.errorRequired', {
    myKey: 'value!',
  })

  return <>MyComponent</>
}

<Form.Handler locale="en-GB" translations={myTranslations}>
  <MyComponent />
</Form.Handler>
```

---------

Co-authored-by: Anders <[email protected]>
  • Loading branch information
tujoworker and langz authored Oct 15, 2024
1 parent ca15887 commit 6f40922
Show file tree
Hide file tree
Showing 12 changed files with 762 additions and 181 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: 'useTranslation'
description: '`Form.useTranslation` is a hook that returns the translations for the current locale.'
showTabs: true
tabs:
- title: Info
key: '/info'
- title: Demos
key: '/demos'
breadcrumb:
- text: Forms
href: /uilib/extensions/forms/
- text: Form
href: /uilib/extensions/forms/Form/
- text: Form.useTranslation
href: /uilib/extensions/forms/Form/useTranslation/
---

import Info from 'Docs/uilib/extensions/forms/Form/useTranslation/info'
import Demos from 'Docs/uilib/extensions/forms/Form/useTranslation/demos'

<Info />
<Demos />
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
// @ts-nocheck
import React from 'react'
import ComponentBox from '../../../../../../shared/tags/ComponentBox'
import { Form } from '@dnb/eufemia/src/extensions/forms'

export const CustomTranslations = () => {
return (
<ComponentBox>
{() => {
const MyField = () => {
const { Custom, formatMessage } = Form.useTranslation()

const myTranslation = formatMessage(Custom.translation, {
myKey: 'value!',
})
console.log('Custom', myTranslation)

return <>{myTranslation}</>
}

const MyForm = () => {
return (
<Form.Handler
locale="en-GB"
translations={{
'en-GB': {
Custom: { translation: 'My translation with a {myKey}' },
},
}}
>
<MyField />
</Form.Handler>
)
}

return <MyForm />
}}
</ComponentBox>
)
}

export const GetTranslation = () => {
return (
<ComponentBox>
{() => {
const MyField = () => {
const { formatMessage } = Form.useTranslation()

const myTranslation = formatMessage('Custom.translation', {
myKey: 'value!',
})
const errorRequired = formatMessage('Field.errorRequired')
console.log(errorRequired)

return <>{myTranslation}</>
}

const MyForm = () => {
return (
<Form.Handler
locale="en-GB"
translations={{
'en-GB': {
Custom: { translation: 'My translation with a {myKey}' },
},
}}
>
<MyField />
</Form.Handler>
)
}

return <MyForm />
}}
</ComponentBox>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
showTabs: true
---

import * as Examples from './Examples'

## Demos

### Custom translations example

<Examples.CustomTranslations />

### Get translations with a key

<Examples.GetTranslation />
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
showTabs: true
---

## Description

The `Form.useTranslation` is a hook that returns the translations for the current locale.

```tsx
import { Form } from '@dnb/eufemia/extensions/forms'

function MyComponent() {
const { Field } = Form.useTranslation()
const { errorRequired } = Field

return <>MyComponent</>
}

render(
<Form.Handler locale="en-GB">
<MyComponent />
</Form.Handler>,
)
```

## Additional utilities

In addition to all internal translations, you also get;

- `formatMessage` - a function you can use to get a specific translation based on a key (flattened object with dot-notation).

```tsx
import { Form } from '@dnb/eufemia/extensions/forms'

function MyComponent() {
const { formatMessage } = Form.useTranslation()
const errorRequired = formatMessage('Field.errorRequired')

return <>MyComponent</>
}

render(
<Form.Handler locale="en-GB">
<MyComponent />
</Form.Handler>,
)
```

## Custom translations

You can also extend the translations with your own custom translations.

```tsx
import { Form } from '@dnb/eufemia/extensions/forms'

const myTranslations = {
'nb-NO': { myString: 'Min egendefinerte streng' },
'en-GB': {
// Cascaded translations
Nested: {
stringWithArgs: 'My custom string with an argument: {myKey}',
},

// Flat translations
'Nested.stringWithArgs': 'My custom string with an argument: {myKey}',
},
}

const MyComponent = () => {
const t = Form.useTranslation<typeof myTranslations>()

// Internal translations
const existingString = t.Field.errorRequired

// Your translations
const myString = t.myString

// Use the "formatMessage" function to handle strings with arguments
const myStringWithArgsA = t.formatMessage(t.Nested.stringWithArgs, {
myKey: 'myValue',
})
// You can also get the string with a key (dot-notation)
const myStringWithArgsB = t.formatMessage('Nested.stringWithArgs', {
myKey: 'myValue',
})

return <>MyComponent</>
}

render(
<Form.Handler translations={myTranslations}>
<MyComponent />
</Form.Handler>,
)
```

## Using the `<Translation />`

Instead of using the hook, you can also, use the `<Translation />` component to consume your translations:

```tsx
import { Form } from '@dnb/eufemia/extensions/forms'
import { Translation, TranslationProps } from '@dnb/eufemia/shared'

const myTranslations = {
'nb-NO': { 'custom.string': 'Min egendefinerte streng' },
'en-GB': { 'custom.string': 'My custom string' },
}

// For TypeScript support
type Tr<T> = TranslationProps<T[keyof T]>
const Tr = (props: Tr<typeof myTranslations>) => <Translation {...props} />

render(
<Form.Handler translations={myTranslations}>
<Form.MainHeading>
<Translation id="custom.string" />
</Form.MainHeading>

<Form.SubHeading>
<Tr id={(t) => t.custom.string} />
</Form.SubHeading>
</Form.Handler>,
)
```

## Use the shared Provider to customize translations

```tsx
import { Form, Field } from '@dnb/eufemia/extensions/forms'
import { Provider, Translation } from '@dnb/eufemia/shared'

const myTranslations = {
'nb-NO': {
'PhoneNumber.label': 'Egendefinert',
'custom.string': 'Min egendefinerte streng',
},
'en-GB': {
'PhoneNumber.label': 'Custom',
'custom.string': 'My custom string',
},
}

render(
<Provider translations={myTranslations}>
<Heading>
<Translation id="custom.string" />
</Heading>

<Form.Handler>
<Field.PhoneNumber />
</Form.Handler>
</Provider>,
)
```
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ You can also use a [FieldBlock](/uilib/extensions/forms/create-component/FieldBl

## Localization and translations

You can use the `Form.useTranslation` hook to use existing translations or extend it with your custom field localization:
You can use the [Form.useTranslation](/uilib/extensions/forms/Form/useTranslation/) hook to use existing translations or extend it with your custom field localization:

```tsx
import {
Expand Down
Loading

0 comments on commit 6f40922

Please sign in to comment.