DeepL Translate TYPO3 extension 

Extension key

dd_deepl

Package name

dmitryd/dd-deepl

Version

main

Language

en

Author

Dmitry Dulepov

License

This document is published under the Creative Commons BY 4.0 license.

Rendered

Tue, 28 Apr 2026 14:13:52 +0000


This extension translates TYPO3 content elements and records using DeepL.


Table of Contents:

Introduction 

What does it do? 

This extension translates TYPO3 content and records using the DeepL translation service. You will need to register an account with DeepL.

Why this extension? 

There are other similar extensions to this. One is EXT:deepltranslate, which is the first extension of the kind. It works for TYPO3 versions 8 and 9 but not later. There is a fork of this extension by web-vision GmbH named EXT:wv_deepltranslate. This extension works with newer TYPO3 versions but it inherits a lot of old legacy code. While developers at web-vision did a great job supporting and developing the fork, this extension follows a separate implementation.

Other extensions do not allow you to modify the translation process, for example to inspect and change field values before and after translation, or to force or prevent translation of the field. This extension provides several events that can alter translation behavior or modify field values before and after the translation.

The extension can translate FlexForm fields, including sections. This is useful for custom content elements.

This extension is not in any way based on two above mentioned extensions or contains any of their code. This is completely new code.

Source code, bugs, etc 

The project is hosted on GitHub at https://github.com/dmitryd/dd_deepl. Questions are not answered in the bug tracker. Use TYPO3 Slack for questions and answers.

Installation 

Install the extension in a TYPO3 14 Composer installation:

composer require "dmitryd/dd-deepl"
Copied!

Go to https://www.deepl.com/signup and sign up. Get a free API key.

Configure DeepL in the site configuration:

ddDeepl:
  apiKey: '%env(TYPO3_DEEPL_API_KEY)%'
  timeout: 30
  maximumNumberOfGlossariesPerLanguage: 2
  glossaries:
    de-en: '1a7170f3-edab-4c66-949a-4db3dc6a233f'
Copied!

If the environment variable is not set, DeepL is treated as disabled for that site.

Legacy TypoScript configuration is available only as a deprecated opt-in fallback. See Migration before using it.

Configuration 

Configure the extension in the site configuration:

ddDeepl:
  apiKey: '%env(TYPO3_DEEPL_API_KEY)%'
  timeout: 30
  maximumNumberOfGlossariesPerLanguage: 2
  glossaries:
    de-en: '1a7170f3-edab-4c66-949a-4db3dc6a233f'
Copied!

If the ddDeepl key is missing, DeepL is disabled for that site.

Site configuration reference 

Name Type Default
string empty
integer 30
integer 2
map empty

ddDeepl.apiKey

ddDeepl.apiKey
Type
string
Default
empty

DeepL API key for the site. Free API keys end with :fx and automatically use the DeepL free API endpoint.

The value can use a TYPO3 environment placeholder, for example %env(TYPO3_DEEPL_API_KEY)%. If the placeholder is still unresolved at runtime, the API key is treated as empty, DeepL is disabled for the site, and a notice is written to the TYPO3 log.

ddDeepl.timeout

ddDeepl.timeout
Type
integer
Default
30

Timeout in seconds for network requests to DeepL. Values are limited to the effective range from 3 to 60.

Larger pages may perform many DeepL requests. If DeepL does not respond before the timeout, the affected localized records are removed again so editors can retry them later. The technical error details are written to the TYPO3 log.

ddDeepl.maximumNumberOfGlossariesPerLanguage

ddDeepl.maximumNumberOfGlossariesPerLanguage
Type
integer
Default
2

Maximum number of DeepL glossaries that can be created per language pair through this extension.

ddDeepl.glossaries

ddDeepl.glossaries
Type
map
Default
empty

Maps a language pair to a glossary id. The key format is source-target, for example de-en.

TypoScript reference 

Deprecated since version 14.0

TypoScript configuration is only used when the extension configuration option configurationSource is set to legacyTypoScript. Legacy mode emits a deprecation warning. There is no automatic fallback from site configuration to TypoScript.

Constants 

apiKey

apiKey
type

string

Default

empty

This is an API key for DeepL.

Example:

module.tx_dddeepl.settings.apiKey = <your value here>
Copied!

maximumNumberOfGlossariesPerLanguage

maximumNumberOfGlossariesPerLanguage
type

integer

Default

2

Maximum number of glossaries that can be added.

Example:

module.tx_dddeepl.settings.maximumNumberOfGlossariesPerLanguage = 2
Copied!

timeout

timeout
type

integer

Default

10

How long to wait for network requests to DeepL servers

Example:

module.tx_dddeepl.settings.timeout = 5
Copied!

Setup 

apiKey

apiKey
type

string / stdWrap

Default

empty

Default is a constant. If there is an environment variable named TYPO3_DEEPL_API_KEY, it will be used instead.

glossaries

glossaries
type

array

Default

empty

An array of mappings between language pairs and glossary id values. You can find glossary id in the Backend module or in the output of the glossary console command (see How to manage glossaries). In most cases DeepL uses the glossary automatically, but sometimes you need to specify it to be used for translations.

Example:

module.tx_dddeepl {
  settings {
    glossaries {
      de-en = 1a7170f3-edab-4c66-949a-4db3dc6a233f
      de-fr = 00526740-a941-414c-8bbe-6aa69e619222
      de-it = 513e3440-0704-11ef-b551-6a4a7949937b
    }
  }
}
Copied!

maximumNumberOfGlossariesPerLanguage

maximumNumberOfGlossariesPerLanguage
type

integer

Default

{$module.tx_dddeepl.settings.maximumNumberOfGlossariesPerLanguage}

Maximum number of glossaries that can be added.

timeout

timeout
type

integer

Default

{$module.tx_dddeepl.settings.timeout}

How long to wait for network requests to DeepL servers

Example:

module.tx_dddeepl.settings.timeout = 5
Copied!

TSConfig reference 

Page TSConfig 

localization.enableDeepL 

Datatype
boolean
Description
Enables DeepL as a TYPO3 localization handler in the localization wizard. Note that direct DataHandler translations are not affected by this option.
Default
1
Example
mod {
   web_layout {
       localization.enableDeepL = 1
   }
}
Copied!

Migration 

Version 14 uses site configuration as the default configuration source. Existing TypoScript settings are not read unless legacy mode is explicitly enabled.

Migrate TypoScript settings 

Move the former TypoScript settings to the ddDeepl key in the site configuration:

module.tx_dddeepl.settings.apiKey = your-api-key
module.tx_dddeepl.settings.timeout = 30
module.tx_dddeepl.settings.maximumNumberOfGlossariesPerLanguage = 2
module.tx_dddeepl.settings.glossaries.de-en = 1a7170f3-edab-4c66-949a-4db3dc6a233f
Copied!
ddDeepl:
  apiKey: '%env(TYPO3_DEEPL_API_KEY)%'
  timeout: 30
  maximumNumberOfGlossariesPerLanguage: 2
  glossaries:
    de-en: '1a7170f3-edab-4c66-949a-4db3dc6a233f'
Copied!

The ddDeepl.apiKey value should normally use an environment variable so the secret is not stored in the site configuration file.

Temporary legacy mode 

Legacy TypoScript configuration can be enabled temporarily in the extension configuration. In Composer-based TYPO3 installations this configuration can be set in config/system/additional.php:

<?php

$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['dd_deepl']['configurationSource'] = 'legacyTypoScript';
Copied!

The same value can also be stored through the TYPO3 extension configuration UI, if it is available in the project. The resulting configuration value must be:

$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['dd_deepl']['configurationSource']
    = 'legacyTypoScript'
Copied!

This mode is deprecated, emits a deprecation warning, and should only be used as a temporary rollback path while migrating site configuration. There is no automatic fallback from site configuration to TypoScript.

For Integrators 

Integrators can do the following with the extension:

  • Add configuration (API key)
  • Manage glossaries

Add configuration 

In order to use DeepL, you need to obtain the API key and configure it in the extension. There are two types of the API key: free and paid.

Free API key is useful for development and testing. It has enough limits for both these tasks. Free key ends with :fx.

Paid API key has much higher limits. It is meant to be used in production.

To obtain the API key you need to register with DeepL and get the key in your DeepL account settings.

Add the API key to the site configuration under ddDeepl.apiKey. The value can use TYPO3 environment placeholders, for example %env(TYPO3_DEEPL_API_KEY)%. Environment variables are recommended because they keep secrets out of the site configuration file.

Legacy TypoScript configuration can still be enabled as a deprecated temporary fallback. See Migration.

Translation errors and retries 

DeepL translations are executed while TYPO3 creates localized records. If a single content element or related record cannot be translated, the extension removes that localized record again instead of keeping a translated record with original text.

Editors see a generic message that some elements were not translated and can retry the translation later. Technical details, including the table, record identifier, field identifier and DeepL exception message, are written to the TYPO3 log.

The timeout for DeepL requests is configured with ddDeepl.timeout. The default timeout is 30 seconds.

Manage glossaries 

Glossaries are a way in DeepL to specify alternative translations to certain words. Some words can have generic accepted translations, but if your site is specific to a certain industry or activity, then words of one language may map to something other than DeepL would typically produce. This is where glossaries come in. They contain word pairs that map source words to target words.

DeepL supports glossaries for various language pairs. There can be multiple glossaries per language combination. The extension allows you to add, delete, download and remove glossaries, and to see what glossaries you have.

The extension allows you to specify the limit on the amount of glossaries per language pair. While DeepL itself does not impose any limits, it is good to have that number under control. Use ddDeepl.maximumNumberOfGlossariesPerLanguage in site configuration.

How to manage glossaries 

Glossary management happens via the shell command or Backend module.

When the command is executed without --site or --root, the extension auto-selects the site only if the TYPO3 instance has exactly one configured site. Instances with multiple sites must pass either --site or --root. Passing both options is an error.

Here is the output of the shell command's help screen:

$ vendor/bin/typo3 deepl:glossary --help
Description:
  Uploads, downloads, lists, or deletes DeepL glossaries using account settings in the current TYPO3 version

Usage:
  deepl:glossary [options] [--] <action>
  This command manages DeepL glossaries.

Usage:
  vendor/bin/typo3 deepl:glossary info
    Fetches information about supported language combinations and existing glossaries.
  vendor/bin/typo3 deepl:glossary add -f file.csv -g "My glossary" -s en-us -t de
    Adds a glossary.
  vendor/bin/typo3 deepl:glossary get -i a1b33a94-ec7e-4ef5-8830-2f7309fab155
    Fetches the glossary by its id. To see the id use the "info" command. Fetched file will be named according to the id.
  vendor/bin/typo3 deepl:glossary delete -i a1b33a94-ec7e-4ef5-8830-2f7309fab155
    Removes the glossary by its id. To see the id use the "info" command.

Arguments:
  action                                   What to do: add, get, delete glossaries or show the information

Options:
  -f, --file[=FILE]                        Glossary in CSV format
  -i, --id[=ID]                            Glossary id
  -g, --name[=NAME]                        Glossary name
  -r, --root[=ROOT]                        Root page id to use (if your instance has more than one)
      --site[=SITE]                        Site identifier to use (if your instance has more than one)
  -s, --source-language[=SOURCE-LANGUAGE]  Source language
  -t, --target-language[=TARGET-LANGUAGE]  Target language
Copied!

Backend module 

There is also a Backend module where it is possible to view current API limits as well as information about uploaded glossaries. You can also upload glossaries via this module.

The module is available as Site > DeepL in the main menu.

For Editors 

Editors can translate content and records using DeepL.

Start the regular TYPO3 localization wizard from the Page module or from a record localization button. Select DeepL as the localization handler when the wizard asks how the localization should be processed.

DeepL does not add a separate localization button. It is available as an option in the standard TYPO3 localization wizard.

Records will get translations if the combination of source and target language is supported by DeepL.

Large translations 

When a page contains many content elements, the localization wizard shows a warning before the DeepL translation starts. Translating many elements can take longer and may increase the chance of DeepL API timeouts.

If some elements cannot be translated due to DeepL errors, they are removed from the localized page again. You can start the localization wizard later and try translating those elements again.

For Developers 

You can use the DmitrydDdDeeplServiceDeeplTranslationService class to translate TYPO3 records, certain fields, or plain texts. Records must have an entry in $GLOBALS['TCA'].

Create the service through dependency injection or GeneralUtility::makeInstance(). If the current request does not contain a site context, call setSite() before invoking DeepL operations.

If no site can be resolved, or if the site has no ddDeepl.apiKey, DeepL is treated as disabled.

There are several events that can alter the behavior of the service. You can use them to get notified about translations, force or prevent a field from being translated, or alter the field value before and after it is sent to DeepL.

API 

Translation service 

class DeeplTranslationService
Fully qualified name
\Dmitryd\DdDeepl\Service\DeeplTranslationService

This is the class you, as a developer, would use to translate data using DeepL.

__construct ( array $deeplOptions = [], ?FrontendInterface $runtimeCache = null, ?ConfigurationFactory $configurationFactory = null)

Creates the instance of the class. You can pass additional DeepL options as described in the DeepL documentation. The runtime cache and configuration factory are injected by TYPO3 during normal service creation.

setSite ( ?Site $site) : self
returntype

self

Sets the site context for the next DeepL operations. Use this method for CLI tasks, backend actions without a request site attribute, or custom integrations that already know the target site.

Returns

The current service instance.

isAvailable ( ) : bool
returntype

bool

Returns

true if DeepL can process requests with the current site configuration and API limits.

translateRecord ( string $tableName, array $record, SiteLanguage $targetLanguage, array $exceptFieldNames = []) : array
returntype

array

The method will go through each field in the record, evaluate if it can be translated and call DeepL for translation. The result is an array with translations.

Returns

Array with translated fields

translateField ( string $tableName, string $fieldName, string $fieldValue, SiteLanguage $sourceLanguage, SiteLanguage $targetLanguage) : string
returntype

string

The method will get the value of the field and call DeepL for translation. Unlike in translateRecord(), there are no checks if the field can be translated.

Returns

Translated field value

translateText ( string $text, string $sourceLanguage, string $targetLanguage) : string
returntype

string

The method will get the text and call DeepL for translation.

Returns

Translated field value

Events 

class AfterFieldTranslatedEvent
Fully qualified name
\Dmitryd\DdDeepl\Event\AfterFieldTranslatedEvent

This event is fired after the field was translated by translateRecord or translateField and allows to modify the translated value.

getTableName ( ) : string
returntype

string

Returns

Table name of the field

getFieldName ( ) : string
returntype

string

Returns

The field name

getFieldValue ( ) : string
returntype

string

Returns

The current (translated) field value

getSourceLanguage ( ) : SiteLanguage
returntype

\TYPO3\CMS\Core\Site\Entity\SiteLanguage

Returns

Source language to translate from

getTargetLanguage ( ) : SiteLanguage
returntype

\TYPO3\CMS\Core\Site\Entity\SiteLanguage

Returns

Target language to translate to

setFieldValue ( string $fieldValue) : void

Sets the new value of the field.

class AfterRecordTranslatedEvent
Fully qualified name
\Dmitryd\DdDeepl\Event\AfterRecordTranslatedEvent

This event is fired after the record was translated by translateRecord. You can examine fields and alter their contents by using getTranslatedFields and setTranslatedFields. Note that there is no method for getting the source language because you can get this information from the record.

getTableName ( ) : string
returntype

string

Returns

Table name of the field

getRecord ( ) : array
returntype

array

Returns

Original (non-translated) record

getTargetLanguage ( ) : SiteLanguage
returntype

\TYPO3\CMS\Core\Site\Entity\SiteLanguage

Returns

Target language to translate to

getTranslatedFields ( ) : array
returntype

array

Returns

The current (translated) field values

setTranslatedFields ( array $translatedFields) : void

Replaces translated fields with a new array of fields.

class BeforeFieldTranslationEvent
Fully qualified name
\Dmitryd\DdDeepl\Event\BeforeFieldTranslationEvent

This event is fired before the field is translated by translateRecord or translateField and allows to modify the original field value before it is sent to DeepL.

getTableName ( ) : string
returntype

string

Returns

Table name of the field

getFieldName ( ) : string
returntype

string

Returns

The field name

getFieldValue ( ) : string
returntype

string

Returns

The current field value

getSourceLanguage ( ) : SiteLanguage
returntype

\TYPO3\CMS\Core\Site\Entity\SiteLanguage

Returns

Source language to translate from

getTargetLanguage ( ) : SiteLanguage
returntype

\TYPO3\CMS\Core\Site\Entity\SiteLanguage

Returns

Target language to translate to

setFieldValue ( string $fieldValue) : void

Sets the new value of the field.

class BeforeRecordTranslationEvent
Fully qualified name
\Dmitryd\DdDeepl\Event\BeforeRecordTranslationEvent

This event is fired before the record is translated by translateRecord. You can examine fields and alter their contents by using getTranslatedFields and setTranslatedFields. Note that there is no method for getting the source language because you can get this information from the record.

getTableName ( ) : string
returntype

string

Returns

Table name of the field

getRecord ( ) : array
returntype

array

Returns

Original (non-translated) record

getTargetLanguage ( ) : SiteLanguage
returntype

\TYPO3\CMS\Core\Site\Entity\SiteLanguage

Returns

Target language to translate to

getTranslatedFields ( ) : array
returntype

array

Returns

The current field values

setTranslatedFields ( array $translatedFields) : void

Replaces translated fields with a new array of fields.

class CanFieldBeTranslatedCheckEvent
Fully qualified name
\Dmitryd\DdDeepl\Event\CanFieldBeTranslatedCheckEvent

This event is fired after the DeepL translation service evaluated whether the field can be translated.

getTableName ( ) : string
returntype

string

Returns

Table name of the field

getFieldName ( ) : string
returntype

string

Returns

The field name

getCanBeTranslated ( )
returntype

bool|null

Returns

true, if the service thinks that the field can be translated, false, if definitely not, null, if the service could not decide.

setCanBeTranslated ( ) : void

Pass true, if the service thinks that the field can be translated, false, if not. Note that you cannot pass null here. If you are unsure, do not set any value. The service will not translate the field unless the value after all events is set to true.

class PreprocessFieldValueEvent
Fully qualified name
\Dmitryd\DdDeepl\Event\PreprocessFieldValueEvent

This event is fired before the field is set to DeepL for translation and allows you to modify the value. A typical example would be, for example, doing data clean up or replacing &nbsp; with a normal space in texts, or removing several <br> tags.

getTableName ( ) : string
returntype

string

Returns

Table name of the field

getFieldName ( ) : string
returntype

string

Returns

The field name

getFieldValue ( ) : string
returntype

string

Returns

The current field value

setFieldValue ( string $fieldValue) : void

Sets the new value of the field.

Examples 

Translating a record:

$languageId = 1;
$newsId = 1;
$newsRecord = BackendUtility::getRecord('tx_news_domain_model_news', $newsId);
$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($newsRecord['pid']);
$targetLanguage = $site->getLanguageById($languageId);
$service = GeneralUtility::makeInstance(\Dmitryd\DdDeepl\Service\DeeplTranslationService::class);
$translatedFields = $service->translateRecord('tx_news_domain_model_news', $newsRecord, $targetLanguage);
Copied!

Sitemap