numero2 / contao-deepl
DeepL powered translations in the Contao Backend.
Requires
- contao/core-bundle: ^5.3 || ^6.0
- deeplcom/deepl-php: ^1.8
- symfony/cache-contracts: ^3.0
- symfony/config: ^6.4 || ^7.0 || ^8.0
- symfony/dependency-injection: ^6.4 || ^7.0 || ^8.0
- symfony/event-dispatcher: ^6.4 || ^7.0 || ^8.0
- symfony/http-foundation: ^6.4 || ^7.0 || ^8.0
- symfony/http-kernel: ^6.4 || ^7.0 || ^8.0
- symfony/intl: ^6.4 || ^7.0 || ^8.0
- symfony/routing: ^6.4 || ^7.0 || ^8.0
- symfony/translation-contracts: ^3.0
Requires (Dev)
- contao/manager-plugin: ^2.0
Suggests
None
Provides
None
Conflicts
- contao/core: *
- contao/manager-plugin: <2.0 || >=3.0
Replaces
None
README
About
This extension allows you to translate individual fields within a DCA (Data Container Array) with just one click, leveraging the DeepL API for accurate translations. It also includes caching of previously translated texts to optimize performance and minimize API calls.
System requirements
- Contao 5.3 (or newer)
- DeepL API Key (free or paid plan)
Installation & Configuration
- Install the extension via Contao Manager or Composer (
composer require numero2/contao-deepl) - Add your DeepL API Key to your
.envDEEPL_API_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - Alternatively, you can add the API key to your
config/config.yaml
deepl:
api_key: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx'
- A preferred mapping can be created for language variants (e.g. British English en-GB, Brazilian Portuguese pt-BR, etc.). The exact language code to be used can be found at Deepl.com.
deepl:
api_key: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx'
pref_lang:
en:en-GB
pt:pt-BR
Glossaries
A glossary keeps your terminology out of the translation: product names, brand terms, wording that must stay as it is. Create and maintain the glossaries in the DeepL web app and reference their IDs per language pair, written in base language codes:
deepl:
api_key: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx'
source_lang: 'de'
glossaries:
de-en: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
de-fr: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
DeepL only accepts a glossary when the source language is explicit, so a source language has to be known. It is determined in this order:
- The fallback language of the site the record belongs to. In the usual multilingual setup — one language tree per language, one of them the fallback — that is the language you translate from, and it is derived per site, so an installation hosting several sites in different main languages gets the right answer for each. Nothing to configure.
source_lang, when the first yields nothing. That happens when a root page is its own fallback, which is the normal shape of a one-domain-per- language setup.
If neither yields a language, the text is translated without a glossary rather than with a guessed source. A wrong source language means DeepL silently finds no glossary for the pair, and nobody notices that the terminology was not applied.
Glossaries exist for base languages only (en, not en-US), so the regional
variant is stripped for the lookup while the translation itself keeps the full
target code.
Usage
After installation, each field that can be translated will display a small DeepL translation icon next to its label. Once clicked, DeepL will automatically translate the text in the field to match the language of your current page settings.
💡 Hint: You can also translate all fields at once by pressing ALT+T on Windows or Option+T on Mac.
Which fields are translated
A button needs a target language first. It is determined by a language
resolver from the page tree the record belongs to. The bundled resolvers cover
pages, articles, forms, news and events, including their content elements.
Records of other extensions that have no link to a page (a store locator, for
instance) get no button at all until a resolver for them is registered: a
service implementing LanguageResolverInterface, picked up automatically.
Within a table that has a resolver, whether a field gets a translation button is derived from its DCA, so fields of other extensions are handled the same way as core fields. The first rule that applies wins: c
deepl:
fields:
tl_content.embed: false # never translate
tl_form_field.value: true # translate, although excluded by default
'*.subheadline': false # never translate, in any table
If you maintain an extension, mark a field in its DCA instead:
$GLOBALS['TL_DCA']['tl_my_table']['fields']['token']['translate'] = false; $GLOBALS['TL_DCA']['tl_my_table']['fields']['label']['translate'] = true;
To see what is offered for translation and why, run:
vendor/bin/contao-console debug:deepl-fields tl_content
Without a table name it lists all tables supported out of the box; --all
also shows the fields skipped for their input type.
The command first checks whether a language resolver handles the table. If
none does, it warns instead of listing fields, since no button would appear
anyway. For tl_content it also lists every parent table found in the database
and whether content below it can be resolved. To make your own resolver show
up there, also implement TableAwareResolverInterface and declare its tables
in supportsTable(); resolvers without it are reported as "unknown".
Supported bundles
This extension supports the following Contao bundles:
