---
title: 'Form.useTranslation'
description: '`Form.useTranslation` is a hook that returns the translations for the current locale.'
version: 10.104.0
generatedAt: 2026-04-17T18:46:12.399Z
checksum: 090b7d977ba4be5e2c4c04d199a30a4048416c59f443a56985df2f80629d9c40
---

# Form.useTranslation

## Import

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

## 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).
- `renderMessage` - a function you can use to render a string with line-breaks. It converts `{br}` to a JSX line-break.

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

function MyComponent() {
  const { formatMessage, renderMessage } = 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.stringWithLinebreaks':
      'My custom string with a {br}line-break',
  },
}

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',
  })

  // Render line-breaks
  const jsxOutput = t.renderMessage(t.Nested.stringWithLinebreaks)

  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' },
}
type TranslationType = (typeof myTranslations)[keyof typeof myTranslations]

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

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

### Formatting markers inside `<Translation />`

`<Translation />` automatically applies simple formatting markers in strings (using the shared `renderWithFormatting`):

- `{br}` inserts a line break
- `**bold**`, `_italic_`, `` `code` ``
- links `[label](https://…)` and bare URLs `https://…`

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

const myTranslations = {
  'en-GB': {
    info: 'Use **bold** and _italic_ with a {br}line-break.',
  },
}
type TranslationType = (typeof myTranslations)[keyof typeof myTranslations]

render(
  <Form.Handler translations={myTranslations} locale="en-GB">
    <Translation<TranslationType> id={(t) => t.info} />
  </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',
  },
}
type TranslationType = (typeof myTranslations)[keyof typeof myTranslations]

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

    <Form.Handler>
      <Field.PhoneNumber />
    </Form.Handler>
  </Provider>
)
```

## Fallback for missing or partial translations

`Form.useTranslation` will output missing keys when:

- Empty explicit locale: returns pointer strings (e.g. `MyNamespace.label`) derived from `fallbackLocale="nb-NO"`.
- Partial explicit locale: merges missing keys as pointer strings, preserving existing ones.
- Non-existent current locale (no explicit entry in your translations): the hook preserves defaults (no pointers).

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

const translations = {
  'sv-SE': {}, // empty explicit current-locale
  'en-GB': { MyNamespace: { label: 'English label' } },
}

type T = (typeof translations)['en-GB']

function MyField() {
  const t = Form.useTranslation<T>({
    fallbackLocale: 'en-GB', // default: 'nb-NO'
  })
  return <>{t.MyNamespace.label /* 'MyNamespace.label' */}</>
}

render(
  <Form.Handler locale="sv-SE" translations={translations}>
    <MyField />
  </Form.Handler>
)
```

### Formatted messages

For richer inline formatting inside form translations, use the `renderWithFormatting` helper from `@dnb/eufemia/shared`.

More info about the supported formatting in the [renderWithFormatting documentation](/uilib/usage/customisation/localization/#formatted-messages).

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

const translations = {
  'en-GB': {
    'Field.info': 'Fill out the **form** and _submit_ {br}when ready.',
  },
}

type T = (typeof translations)['en-GB']

function MyComponent() {
  const t = Form.useTranslation<T>()

  return <>{renderWithFormatting(t.Field.info)}</>
}

function MyApp() {
  return (
    <Form.Handler translations={translations} locale="en-GB">
      <MyComponent />
    </Form.Handler>
  )
}
```

## Demos

### Custom translations example

```tsx
const MyField = () => {
  type Translation = {
    Custom: {
      translation: string
    }
  }
  const { Custom, formatMessage } = Form.useTranslation<Translation>()
  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>
  )
}
render(<MyForm />)
```

### Get translations with a key

```tsx
const MyField = () => {
  type Translation = {
    Custom: {
      translation: string
    }
  }
  const { formatMessage } = Form.useTranslation<Translation>()
  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>
  )
}
render(<MyForm />)
```
