Hooks

Use the Content Translator plugin hooks to customize translation behavior.

The Kirby Content Translator plugin provides powerful hooks that allow you to customize the translation process. These hooks enable you to modify text before and after translation, implement custom logic, or integrate with other systems.

Available Hooks

content-translator.translate:before

This hook is triggered before any text is translated. It allows you to modify the text that will be sent to the translation service, apply preprocessing logic, or even prevent translation entirely.

Arguments:

  • text (string): The original text to be translated
  • targetLanguage (string): The target language code (e.g., 'de', 'fr', 'es')
  • sourceLanguage (string|null): The source language code (can be null if not specified)
  • type (string): Always 'text' for this hook

Return Value:

The hook should return the modified text as a string.

Example Usage:

config.php
return [
    'hooks' => [
        'content-translator.translate:before' => function ($text, $targetLanguage, $sourceLanguage, $type) {
            // Convert specific terms before translation
            $text = str_replace('Company Name', 'Our Company', $text);

            // Skip translation for texts containing certain markers
            if (str_contains($text, '[no-translate]')) {
                return str_replace('[no-translate]', '', $text);
            }

            // Add custom preprocessing
            $text = trim($text);

            return $text;
        }
    ]
];

content-translator.translate:after

This hook is triggered after text has been translated by the translation service. It allows you to modify the translated result, apply post-processing logic, or implement custom formatting.

Arguments:

  • text (string): The translated text returned by the translation service
  • originalText (string): The original text before translation
  • targetLanguage (string): The target language code (e.g., 'de', 'fr', 'es')
  • sourceLanguage (string|null): The source language code (can be null if not specified)
  • type (string): Always 'text' for this hook

Return Value:

The hook should return the modified translated text as a string.

Example Usage:

config.php
return [
    'hooks' => [
        'content-translator.translate:after' => function ($text, $originalText, $targetLanguage, $sourceLanguage, $type) {
            // Apply language-specific formatting
            if ($targetLanguage === 'de') {
                // German-specific formatting
                $text = str_replace('ß', 'ss', $text);
            }

            // Restore certain untranslatable terms
            $patterns = [
                '/API/i' => 'API',
                '/CSS/i' => 'CSS',
                '/HTML/i' => 'HTML',
                '/JavaScript/i' => 'JavaScript',
            ];

            foreach ($patterns as $pattern => $replacement) {
                $text = preg_replace($pattern, $replacement, $text);
            }

            return $text;
        }
    ]
];

Use Cases

Protecting Specific Content

Use the :before hook to protect certain content from being translated:

config.php
return [
    'hooks' => [
        'content-translator.translate:before' => function ($text, $targetLanguage, $sourceLanguage, $type) {
            // Don't translate content wrapped in [preserve] tags
            if (preg_match('/\[preserve\](.*?)\[\/preserve\]/s', $text, $matches)) {
                return $matches[1]; // Return content without translation
            }

            return $text;
        }
    ]
];

Custom Terminology Management

Ensure consistent terminology across translations:

config.php
return [
    'hooks' => [
        'content-translator.translate:after' => function ($text, $originalText, $targetLanguage, $sourceLanguage, $type) {
            $terminology = [
                'de' => [
                    'dashboard' => 'Dashboard', // Keep English term
                    'workflow' => 'Arbeitsablauf',
                    'user interface' => 'Benutzeroberfläche'
                ],
                'fr' => [
                    'dashboard' => 'tableau de bord',
                    'workflow' => 'flux de travail',
                    'user interface' => 'interface utilisateur'
                ]
            ];

            if (isset($terminology[$targetLanguage])) {
                foreach ($terminology[$targetLanguage] as $english => $translation) {
                    $text = str_ireplace($english, $translation, $text);
                }
            }

            return $text;
        }
    ]
];

Integration with External Services

Log translations or send them to external systems:

config.php
return [
    'hooks' => [
        'content-translator.translate:after' => function ($text, $originalText, $targetLanguage, $sourceLanguage, $type) {
            // Send to translation memory system
            if (function_exists('updateTranslationMemory')) {
                updateTranslationMemory($originalText, $text, $sourceLanguage, $targetLanguage);
            }

            // Track translation statistics
            $stats = site()->cache()->get('translation-stats') ?? [];
            $stats[$targetLanguage] = ($stats[$targetLanguage] ?? 0) + 1;
            site()->cache()->set('translation-stats', $stats);

            return $text;
        }
    ]
];

Important Notes

  • Hooks are called for every individual text that gets translated, including content within blocks, structures, and other complex field types.
  • Make sure your hook functions are performant, as they may be called hundreds of times during a batch translation.
  • The hooks apply to all translation operations, whether triggered from the Panel, via the PHP API, or through CLI commands.
  • Hook modifications are applied to the final translated content and will be saved to the content files.
  • Use the type parameter for future compatibility, as it may include different values in future versions of the plugin.
Please be careful when modifying text in hooks, especially in the :after hook. Changes are permanent and will be saved to your content files. Always thoroughly test your hook logic in a development environment.