TYPO3 13/14 Translations
Source: https://github.com/dirnbauer/webconsulting-skills
Use this skill for TYPO3 13 and TYPO3 14 translation files, XLIFF format decisions, localization keys, ICU strings, LLL: references, and v14 translation-domain adoption. Start from the TYPO3 13-compatible baseline, then apply TYPO3 14 upgrades when the extension or project is v14-only.
Core Rules
- For TYPO3 13+14 compatibility, keep XLIFF 1.2 and full
LLL:EXT:
references.
- For TYPO3 14-only work, prefer XLIFF 2.0 and consider translation domains in
PHP where they improve readability.
- Keep one source language file in English, unprefixed, for example
Resources/Private/Language/locallang.xlf or labels.xlf.
- Store target languages beside the source with locale prefixes, for example
de.locallang.xlf, de_CH.locallang.xlf, or de.labels.xlf.
- Do not create
en.locallang.xlf; English is the unprefixed source.
- Keep exactly one
<file> element per XLIFF file.
- Keep one target language per target file.
- Mark approved translations with
approved="yes" in XLIFF 1.2 or
state="reviewed" / state="final" in XLIFF 2.0.
- Treat ICU MessageFormat as TYPO3 14.2+ only; do not use ICU for code that
must run unchanged on TYPO3 13.
- Use TYPO3 localization APIs and Fluid ViewHelpers; do not add custom label
loaders.
Default Workflow
- Inventory source files in
Resources/Private/Language/*.xlf and
ContentBlocks/**/language/*.xlf.
- Inventory consumers in PHP, TCA, YAML, Fluid, TypoScript, TSconfig, and
Content Blocks configuration.
- Decide the compatibility mode:
- TYPO3 13+14: stay on XLIFF 1.2 and LLL:EXT:. - TYPO3 14-only: migrate selected catalogs to XLIFF 2.0 and optionally use domains/ICU.
- Normalize paths, filenames, XML namespaces, and key namespaces.
- Add or migrate labels with natural target-language copy.
- Validate XML, duplicate IDs, source/target parity, and
LLL: resolution.
- Flush TYPO3 caches and smoke-test backend and frontend language contexts.
TYPO3 13-Compatible Baseline
Use this baseline when an extension must support TYPO3 13 and 14.
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="EXT:my_extension/Resources/Private/Language/locallang.xlf" product-name="my_extension">
<header/>
<body>
<trans-unit id="button.save">
<source>Save</source>
</trans-unit>
<trans-unit id="items.count">
<source>Items: %d</source>
</trans-unit>
</body>
</file>
</xliff>
Target file:
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" target-language="de" datatype="plaintext" original="EXT:my_extension/Resources/Private/Language/locallang.xlf" product-name="my_extension">
<header/>
<body>
<trans-unit id="button.save" approved="yes">
<source>Save</source>
<target>Speichern</target>
</trans-unit>
<trans-unit id="items.count" approved="yes">
<source>Items: %d</source>
<target>Eintraege: %d</target>
</trans-unit>
</body>
</file>
</xliff>
TYPO3 13 notes:
- Use
source-language="en" and target-language="<locale>".
- Use
<trans-unit> inside <body>.
- Use
approved="yes" for reviewed translations when approval state matters.
- Use
%s / %d style placeholders and runtime formatting, not ICU.
- Use full
LLL:EXT: references; translation domains are a TYPO3 14 feature.
TYPO3 14 Changes
Use these changes when the project is TYPO3 14-only, or when preparing a v14 branch while keeping the v13 branch on the baseline above.
XLIFF 2.0
Use this source shape for v14-only catalogs:
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">
<file id="messages">
<unit id="button.save">
<segment>
<source>Save</source>
</segment>
</unit>
<unit id="items.count">
<segment>
<source>{count, plural, one {# item} other {# items}}</source>
</segment>
</unit>
</file>
</xliff>
Use this target shape:
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en" trgLang="de">
<file id="messages">
<unit id="button.save">
<segment state="final">
<source>Save</source>
<target>Speichern</target>
</segment>
</unit>
<unit id="items.count">
<segment state="final">
<source>{count, plural, one {# item} other {# items}}</source>
<target>{count, plural, one {# Eintrag} other {# Eintraege}}</target>
</segment>
</unit>
</file>
</xliff>
Migrating XLIFF 1.2 To 2.0
Use this checklist only after the affected label family no longer needs TYPO3 13 compatibility:
- Confirm
composer.json and ext_emconf.php no longer support TYPO3 13.
- Create a branch and convert one label family first.
- Change
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
to <xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en">.
- Remove the XLIFF 1.2
<header> and <body> wrapper.
- Convert each
<trans-unit id="key"> to <unit id="key"><segment>....
- Move
<source> and <target> inside <segment>.
- Convert source-language/target-language attributes to
srcLang/trgLang.
- Convert
approved="yes" to state="reviewed" or state="final".
- Split files that contain more than one
<file> or more than one target
language.
- Preserve unit IDs exactly; change references only when deliberately
renaming keys.
- Validate XML and compare unit IDs between source and every target file.
- Flush TYPO3 caches and verify labels in all affected backend/frontend views.
Do not migrate to a newer XLIFF dialect just because tooling can emit it. For a TYPO3 14-only branch, use the documented XLIFF 2.0 shape unless the project has verified support for another 2.x variant.
ICU MessageFormat
TYPO3 14.2+ supports ICU MessageFormat when translation calls pass named arguments. Store ICU strings as normal XLIFF source and target text.
For TYPO3 13+14 compatibility, avoid ICU and keep classic placeholders. Add ICU only in v14-only code paths or v14-only label files.
Rules:
- Use named placeholders such as
{count} and {name}.
- Do not translate placeholder names.
- Include
other in every plural and select expression.
- Test plural messages with
0, 1, and multiple values.
- Use
LanguageService::translate(), LocalizationUtility::translate(), or
Fluid <f:translate arguments="{...}">; sL() resolves plain labels only.
PHP:
$label = $languageService->translate(
'items.count',
'my_extension.messages',
['count' => 5],
);
Fluid:
<f:translate key="items.count" arguments="{count: itemCount}" />
Paths, Namespaces, And Domains
Use stable file paths and key namespaces so references remain readable during v13-to-v14 upgrades.
File Paths
EXT:my_extension/Resources/Private/Language/messages.xlf
- Traditional extension labels:
EXT:my_extension/Resources/Private/Language/locallang.xlf
EXT:myextension/Resources/Private/Language/locallangdb.xlf
ContentBlocks/<Type>/<name>/language/labels.xlf
Use full LLL:EXT: references where configuration is loaded outside an Extbase context:
'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang_db.xlf:tx_my_table.title',
XML Namespace
Use the XLIFF 2.0 namespace exactly:
xmlns="urn:oasis:names:tc:xliff:document:2.0"
XLIFF IDs Versus TYPO3 14 Domains
Keep the XLIFF unit ID independent from the file/domain reference:
- XLIFF unit ID:
top, button.save, field.ctaText.label.
- TYPO3 14 domain:
myextension.messages, myextension.label,
my_extension.backend.dashboard.
- Combined v14 reference:
my_extension.label:top.
Do not write my_extension.label.top when you mean a TYPO3 14 domain reference. Without the colon, it is just a dotted label ID in the current Extbase/default context.
TYPO3 14 derives domains from language file paths:
| File |
Domain |
Resources/Private/Language/locallang.xlf |
my_extension.messages |
Resources/Private/Language/messages.xlf |
my_extension.messages |
Resources/Private/Language/label.xlf |
my_extension.label |
Resources/Private/Language/locallang_label.xlf |
my_extension.label |
Resources/Private/Language/Backend/locallang_dashboard.xlf |
my_extension.backend.dashboard |
Configuration/Sets/Blog/labels.xlf |
my_extension.sets.blog |
If two files map to the same domain, such as label.xlf and locallang_label.xlf, the simplified filename wins. Avoid these conflicts.
TYPO3 14 Fluid And API Syntax
Use domains for v14-only Fluid templates:
<f:translate domain="my_extension.label" key="top" />
<f:translate key="my_extension.label:top" />
{f:translate(domain: 'my_extension.messages', key: 'button.save')}
Use the same combined syntax in PHP:
$languageService->sL('my_extension.label:top');
$languageService->sL('my_extension.messages:button.save');
For TYPO3 13 compatibility, keep:
<f:translate key="top" extensionName="MyExtension" />
<f:translate key="LLL:EXT:my_extension/Resources/Private/Language/label.xlf:top" />
The v14 domain argument takes precedence over extensionName. Inspect domains with php bin/typo3 language:domain:list when EXT:lowlevel is available.
TYPO3 API First
Use LanguageServiceFactory when a language service must be created explicitly.
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
final readonly class LabelService
{
public function __construct(
private LanguageServiceFactory $languageServiceFactory,
) {}
public function saveLabel(ServerRequestInterface $request): string
{
$languageService = $this->languageServiceFactory->createFromSiteLanguage(
$request->getAttribute('language'),
);
return $languageService->sL(
'LLL:EXT:my_extension/Resources/Private/Language/messages.xlf:button.save',
);
}
}
For backend-only code, $GLOBALS['LANG'] can be used when the backend bootstrap has initialized it. Keep access wrapped in a helper so the dependency is obvious.
Content Blocks Labels
Content Blocks labels commonly live beside the block in ContentBlocks/<Type>/<name>/language/labels.xlf. The source file is labels.xlf; translated files use locale prefixes such as de.labels.xlf.
- Put editor-facing
title and description in the block language file.
- Use field IDs such as
<field>.label and <field>.description.
- Generate or inspect expected keys before editing:
``bash vendor/bin/typo3 content-blocks:language:generate vendor/block --print vendor/bin/typo3 content-blocks:language:generate vendor/block --extension=my_extension ``
- Remember that
labels.xlf overrides inline labels from config.yaml.
- Convert generated v14-only catalogs to XLIFF 2.0 after the key list is known.
Detailed Reference
Read [the full guide](references/full-guide.md) when the task needs detailed examples, long templates, troubleshooting matrices, appendices, or sections not included above. Keep this file unloaded for narrow tasks so the skill follows progressive disclosure.