# Translator

Source code is hosted on [GitHub](https://github.com/corets/schema)

* Works for **server side and client side** translations handling
* Features **static translations access**, without using string based keys
* Extremely **easy to use and customise**
* Not bloated with unnecessary features

{% tabs %}
{% tab title="yarn" %}

```bash
yarn add @corets/translator
```

{% endtab %}

{% tab title="npm" %}

```bash
npm install --save @corets/translator
```

{% endtab %}
{% endtabs %}

Seamless React integration is shipped in a separate package:

{% content-ref url="/pages/-MeeFD9vXhGU6geoh9vx" %}
[useTranslator](/hooks/use-translator.md)
{% endcontent-ref %}

## Static translation access

Translations can be accessed in a static manner thanks to the [`createTranslatorAccessor()`](/services/translator.md#createtranslatoraccessor) helper. Check out [@corets/use-translator](/hooks/use-translator.md#uselocales) docs for an example usage in React.

## Custom interpolations <a href="#custom-interpolations" id="custom-interpolations"></a>

Provide a custom interpolation function used for replacement of placeholders with values:

```typescript
import { createTranslator } from "@corets/translator"

const customInterpolator = (text: string, match: string, replacement: any) => {  
    return text.replace(`[[${match}]]`, replacement)
}
const translator = createTranslator({}, { interpolator: customInterpolator })
```

You can access the default interpolation function anytime:

```typescript
import { translatorInterpolator } from "@corets/translator"
```

## Custom formatting <a href="#custom-formatting" id="custom-formatting"></a>

Provide a custom formatter function used to format replacements before interpolation:

```typescript
import { createTranslator, translatorFormatter } from "@corets/translator"
import dayjs from "dayjs"

const customFormatter = (language: string, replacement: any, replacements: object) => {  
    if (replacement instanceof Date) {    
        const format = replacements?.format ?? "DD.MM.YYYY"    
        
        return dayjs(replacement).format(format)  
    }  
    
    return defaultTranslatorFormatter(language, replacement, replacements)
} 

const translator = createTranslator({}, { formatter: customFormatter })
```

## Custom placeholders <a href="#custom-placeholder-for-missing-keys" id="custom-placeholder-for-missing-keys"></a>

Provide a custom placeholder function used to generate placeholders for missing translation keys:

```typescript
import { createTranslator } from "@corets/translator"

const customPlaceholder = (language: string, key: string, replacements: object) => `${language}.${key}`

const translator = createTranslator({}, { placeholder: customPlaceholder })
```

You can access the default placeholder function anytime:

```typescript
import { translatorPlaceholder } from "@corets/translator"
```

## createTranslator() <a href="#createtranslator" id="createtranslator"></a>

Create a new `Translator` instance:

```typescript
import { createTranslator } from "@corets/translator"

const translations = {  
    en: { title: "Welcome" },  
    de: { title: "Willkommen" }
}

const translator = createTranslator(translations, { language: "en" })
```

Create a translator instance without the factory function:

```typescript
import { Translator } from "@corets/translator"

const translator = new Translator({}, { language: "en" })
```

## createTranslatorAccessor() <a href="#createtranslatoraccessor" id="createtranslatoraccessor"></a>

Create a statically typed facade for your translations. This allows you to access translations in a statically typed manner, no need to use string based translation keys anymore. Trying to access missing translations will lead to a compilation error! 💥

```typescript
import { createTranslator, createTranslatorAccessor } from "@corets/translator"

const translations = {  
    en: { some: { nested: "value", another: "Hello {greeting}"} },  
    de: { some: { nested: "other"} },
}

const translator = createTranslator(translations, { language: "en" })
const locales = createTranslatorAccessor(translator, translations.en)

locales.some.nested.get()
locales.some.another.get({ replace: { greeting: "World" } })
locales.some.nested.get({ language: "de" })
```

This functionality is powered by the accessor library:

{% content-ref url="/pages/-MeeFDZTgmmurCkKtNA3" %}
[Accessor](/services/accessor.md)
{% endcontent-ref %}

## Translator.config() <a href="#translatorconfig" id="translatorconfig"></a>

Configure translator:

```typescript
import { createTranslator } from "@corets/translator"

const translator = createTranslator({ ... }, { language: "en" })

translator.config({  
    language: "en",  
    fallbackLanguage: "de",  
    interpolate: true,  
    formatter,  
    interpolator,  
    placeholder,
})
```

## Translator.getLanguage() <a href="#translatorgetlanguage" id="translatorgetlanguage"></a>

Get current language:

```typescript
translator.getLanguage()
```

## Translator.setLanguage() <a href="#translatorsetlanguage" id="translatorsetlanguage"></a>

Change current language:

```typescript
translator.setLanguage("en")
```

## Translator.getLanguages() <a href="#translatorgetlanguages" id="translatorgetlanguages"></a>

Get all registered languages:

```typescript
translator.getLanguages()
```

## Translator.getFallbackLanguage() <a href="#translatorgetfallbacklanguage" id="translatorgetfallbacklanguage"></a>

Get fallback language:

```typescript
transaltor.getFallbackLanguage()
```

{% hint style="info" %}
A fallback language is used whenever a translation key is missing for current language.
{% endhint %}

## Translator.setFallbackLanguage() <a href="#translatorsetfallbacklanguage" id="translatorsetfallbacklanguage"></a>

Change fallback language:

```typescript
translator.setFallbackLanguage("de")
```

## Translator.getTranslations() <a href="#translatorgettranslations" id="translatorgettranslations"></a>

Get all registered translations:

```typescript
translator.getTranslations()
```

Returned object looks something like this:

```typescript
{  
    en: { key: "value" },  
    de: { key: "value" },
}
```

## Translator.getTranslationsForLanguage() <a href="#translatorgettranslationsforlanguage" id="translatorgettranslationsforlanguage"></a>

Get all translations for a specific language:

```typescript
translator.getTranslationsForLanguage("en")
```

The returned object looks something like this:

```typescript
{ key: "value" }
```

## Translator.setTranslations() <a href="#translatorsettranslations" id="translatorsettranslations"></a>

Replace all translations, for all languages, with the new ones:

```typescript
translator.setTranslations({ en: { key: "value" }})
```

## Translator.setTranslationsForLanguage() <a href="#translatorsettranslationsforlanguage" id="translatorsettranslationsforlanguage"></a>

Replace all translations for a specific language:

```typescript
translator.setTranslationsForLanguage("en", { key: "value" })
```

## Translator.addTranslations() <a href="#translatoraddtranslations" id="translatoraddtranslations"></a>

Update all translations, in all languages, using a merge:

```typescript
translator.addTranslations({ de: { key: "value" } })
```

{% hint style="info" %}
Contrary to the [Translator.setTranslations()](/services/translator.md#translatorsettranslations) method, this one will not replace all translations but do a merge instead.
{% endhint %}

## Translator.addTranslationsForLanguage() <a href="#translatoraddtranslationsforlanguage" id="translatoraddtranslationsforlanguage"></a>

Add translations, for a specific language, using a merge:

```typescript
translator.addTranslationsForLanguage("en", { key: "value" })
```

{% hint style="info" %}
Contrary to the [Translator.setTranslationsForLanguage()](/services/translator.md#translatorsettranslationsforlanguage) method, this one will not replace all translations but do a merge instead.
{% endhint %}

## Translator.get() <a href="#translatorget" id="translatorget"></a>

Retrieve a translation:

```typescript
translator.get("key")
```

Retrieve a translation with a nested key:

```typescript
translator.get("nested.key")
```

Retrieve translation for another language:

```typescript
translator.get("key", { language: "de" })
```

Retrieve translation with another fallback language:

```typescript
translator.get("key", { fallbackLanguage: "de" })
```

Retrieve translation without interpolating it:

```typescript
translator.get("key", { interpolate: false })
```

Retrieve a translation and interpolate some values, using array syntax:

```typescript
// given translation: {{1}} and {{2}} are colors
translator.get("key", ["red", "blue"])
```

Retrieve a translation and interpolate some values, using object syntax:

```typescript
// given translations: {{color1}} and {{color2}} are colors
translator.get("key", { color1: "red", color2: "blue" })
```

Retrieve translation with a custom formatter, interpolator and placeholder:

```typescript
translator.get("key", { formatter, interpolator, placeholder })
```

{% hint style="info" %}
Check out documentation for [formatter](/services/translator.md#custom-formatting), [interpolator](/services/translator.md#custom-interpolations), and [placeholder](/services/translator.md#custom-placeholder-for-missing-keys).
{% endhint %}

## Translator.has() <a href="#translatorhas" id="translatorhas"></a>

Check if translation exists:

```typescript
translator.has("key")
```

Check if translation exists for a specific language:

```typescript
translator.has("key", { language: "en" })
```

Check if translation exists in the current language or in a specific fallback language:

```typescript
translator.has("key", { fallbackLanguage: "de" })
```

## Translator.t() <a href="#translatort" id="translatort"></a>

Create a standalone translation function:

```typescript
const t = translator.t()

t("key")

// same as
translator.get("key")
```

Create a translation function for a specific scope:

```typescript
const t = translator.t("nested.scope")

t("key")

// same as
translator.get("nested.scope.key")
```

Override scope with `~`:

```typescript
const t = translator.t("nested.key")

t("~key")

// same as
translator.get("key")
```

{% hint style="info" %}
This method supports the same options object as [Translator.get()](/services/translator.md#translatorget).
{% endhint %}

## Translator.listen() <a href="#translatorlisten" id="translatorlisten"></a>

Listen to any kind of changes, like language change, translations change, etc.:

```typescript
const unsubscribe = translator.listen(() => console.log("something has changed"))

unsubscribe()
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.corets.io/services/translator.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
