Exceptions

Which failures raise which exception – a dead provider, a misconfigured strategy, a missing key, a language the site never registered.

TranslationException is the plugin's own; the rest are Kirby's. All extend Kirby\Exception\Exception and serialize cleanly to API responses. TranslationException fires only when zero units could be translated – partial failures emit a :warning hook instead.

TranslationException

JohannSchopplich\ContentTranslator\Translation\Exception\TranslationException extends Kirby\Exception\Exception. Built-in strategies throw it when zero units survived – per-unit failures keep the source text and only emit a :warning hook.

public function __construct(
    string $strategy,
    string $reason,
    int $unitsAttempted,
    int $unitsTranslated = 0,
)

Details Payload

The exception carries structured details for logging:

strategy
String
The strategy identifier (deepl, copilot-ai, or your own).
unitsAttempted
Int
How many units the strategy was asked to translate.
unitsTranslated
Int
How many succeeded before the strategy gave up. Always 0 when this exception is thrown.

For per-unit error context, listen to content-translator.translate:warning – it fires for each failed unit with the underlying Throwable before the strategy decides whether enough units survived.

Catching

use JohannSchopplich\ContentTranslator\Translation\Exception\TranslationException;

try {
    $translator->translateContent('de', 'de', 'en');
} catch (TranslationException $error) {
    $details = $error->getDetails();
    // ['strategy' => 'deepl', 'unitsAttempted' => 12, 'unitsTranslated' => 0]
}

An unhandled TranslationException reaches the Panel as HTTP 502.

LogicException

Configuration errors throw Kirby\Exception\LogicException:

TriggerMessage
'strategy' => 'ai' without kirby-copilot installedStrategy "ai" requires the kirby-copilot plugin
'strategy' => 'banana'Unknown strategy "banana"
Kirby language DeepL cannot nameCannot resolve a DeepL target language for Kirby language "…"

A language that resolves to no DeepL code needs a language code override. Other DeepL HTTP error responses map to LogicException – see the DeepL client reference.

InvalidArgumentException

Kirby\Exception\InvalidArgumentException is thrown for a language code the site does not know:

TriggerMessage
Unregistered code on a multi-language siteUnknown language code "…"; not registered in Kirby languages.

Both the translate() helper and Translator::translateText() resolve their $targetLanguage and $sourceLanguage against Kirby's language registry, so a typo in a script surfaces here rather than as a failed request. A single-language site skips the check – any code is passed on to the strategy.

AuthException

Kirby\Exception\AuthException is thrown for missing or rejected API keys:

TriggerMessage
Missing DeepL API keyMissing DeepL API key
DeepL responds with 403Authorization failed. Have you set the correct DeepL API key? …
Missing Copilot AI provider API keyMissing API key in "johannschopplich.copilot.providers.<name>.apiKey"
For per-unit rejections, listen to content-translator.translate:warning instead of catching exceptions.