---
title: "Custom Translator"
description: "Plug in any translation API or local logic – via a closure, a CallableStrategy, or your own Strategy implementation."
canonical_url: "https://kirby.tools/docs/content-translator/providers/custom-translator"
---

# Custom Translator

> Plug in any translation API or local logic – via a closure, a CallableStrategy, or your own Strategy implementation.

When DeepL and Copilot AI don't fit, you can plug in any translation backend. Three options, increasing in capability:

<card-group>
<card icon="i-ri-function-line" title="Closure" to="#option-1-closure">

One translation per text, no batching. Fastest to write.

</card>

<card icon="i-ri-plug-line" title="CallableStrategy" to="/docs/content-translator/php-classes/strategies/callable-strategy">

Same as above, made explicit. The migration target for `translateFn`.

</card>

<card icon="i-ri-stack-line" title="Custom Strategy" to="/docs/content-translator/php-classes/strategies#implementing-a-custom-strategy">

Implement `Strategy` for batching, per-field dispatch, and structured exceptions.

</card>
</card-group>

## Option 1: Closure

The simplest path. Set `strategy` to a closure with the signature `fn (string $text, string $target, ?string $source): string`. The plugin auto-wraps it in `CallableStrategy`.

```php [config.php]
return [
    'johannschopplich.content-translator' => [
        'strategy' => function (string $text, string $toLanguageCode, ?string $fromLanguageCode = null): string {
            return myCustomTranslateFunction($text, $toLanguageCode, $fromLanguageCode);
        }
    ]
];
```

<warning>

A closure runs **once per text**. DeepL and AI strategies batch – this one cannot. For high-volume sites or large batch translations, prefer a custom `Strategy` implementation that batches at the wire level.

</warning>

## Option 2: Custom Strategy

For per-unit failure handling, observability, and access to `TranslationUnit::$fieldKey`, implement the `Strategy` interface directly. See [Implementing a Custom Strategy](/docs/content-translator/php-classes/strategies#implementing-a-custom-strategy) for the full pattern – pre-fill source text, attempt each unit, emit a warning on per-unit failure, throw `TranslationException` only when zero units survived.

<callout color="info" icon="i-ri-arrow-right-line" to="/docs/content-translator/getting-started/migration#translatefn--strategy">

Migrating from the deprecated `translateFn` config? See the **Migration Guide** – it's a one-line rename.

</callout>

---

Every page of this site as Markdown: <https://kirby.tools/sitemap.md>
