For a wording to become translatable through the Back office interface, it has to be made available to it. PrestaShop behaves differently according to whether the wordings belong to the Core or to 3rd party modules & themes.
Wordings from modules and themes (except Native modules and the Classic theme) are automatically scanned from source code at runtime, so you can just use them in the code and they will magically appear in the translation interface — as long as you follow the coding and domain name conventions.
Wordings from the Core (used in Back office, Front office, the Classic theme, Native modules, and built-in Emails) need to be present in the “default” translation catalogue files, located in the ./translations/default
folder. This means that any new Core wording that is used in the code needs to be added there too.
If your new wordings will be included in a release (i.e. if you’re contributing to the project), you don’t need to manually extract and add them to the default catalogue. They will be added by the release manager later, during the preparation for the next minor or major release.
If you are modifying PrestaShop for your own project, you must manually add your new wordings to the default catalogue:
Find the translation file for the domain you are using (eg. translations/default/ShopFormsErrors.xlf
) or create one from scratch if it doesn’t exist.
Add a trans-unit
block for every new wording:
<trans-unit id="cf8092a0be7b972d6cee3db90bfaf923">
<source>You cannot access this store from your country. We apologize for the inconvenience.</source>
<target>You cannot access this store from your country. We apologize for the inconvenience.</target>
<note></note>
</trans-unit>
id
property has no effect on PrestaShop but by convention must be unique. We use an MD5 checksum of the wording itself.<source>
and <target>
must be the same.<trans-unit>
elements within the body of an existing <file>
element, or create a new one — it has no effect.PrestaShop’s TranslationToolsBundle leverages static analysis to detect any new wording in the source code automatically, either at runtime (for modules and themes), or when preparing a release (for core wordings).
To ensure your wordings are detected, make sure to follow these guidelines when using translation in your code:
Only wordings used through the trans()
function, the {l}
Smarty tag, and the trans
Twig filter can be detected automatically. Therefore, only wordings present in .php
, .tpl
, and .twig
files will be detected.
Always pass wordings as string literals, not variables, with the trans()
function, the {l}
Smarty tag, and trans
Twig filter. Although variables would be interpreted at runtime, the code analyzer won’t be able to figure out the link between the symbol and its assigned value. Passing variables as arguments to these functions will prevent those wordings from being detected.
Examples:
<?php
// literal values will work
$this->trans('Some wording', [], 'Admin.Catalog.Feature');
// dynamic content can be injected using placeholders & replacements
$this->trans('Some wording with %foo%', ['%foo%' => $dynamicContent], 'Admin.Catalog.Feature');
// this won't work, the interpreter will ignore variables
$wording = 'Some wording';
$domain = 'Admin.Catalog.Feature';
$this->trans($wording, [], $domain);
// this will yield unexpected results
$this->trans('Some '. $var . ' wording', [], 'Admin.Catalog.Feature');
// dynamic behavior, like aliasing the trans() function, won't work well either
function translate($wording) {
$this->trans($wording, [], 'Admin.Catalog.Feature');
}
In Twig files, you can use trans_default_domain
to set up your default domain. Keep in mind this works on a per-file basis:
{% trans_default_domain 'Admin.Catalog.Feature' %}
{{ 'Hello world'|trans }}
{{ 'Something else'|trans }}
When creating Symfony ChoiceType
form fields:
choices
field as literal (untranslated) strings.choice_translation_domain
as the translation domain for all the choices.<?php
use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class SomeFormType extends TranslatorAwareType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('a_select_box', ChoiceType::class, [
'required' => false,
'label' => $this->trans('This is a select box', 'Admin.Catalog.Feature'),
'choices' => [
'First option' => 0,
'Second option' => 1,
'Third option' => 2,
],
'choice_translation_domain' => 'Admin.Some.Domain',
]);
}
}
The form above declares a Choice field (select box), with three different options.
ChoiceType
declaration to be inside a call to the add()
method, using ChoiceType::class
and not a FQCN. If in doubt, have a look at ChoiceExtractor.You can declare wordings as arrays as well. This obviously won’t translate the wordings at runtime but it will make them discoverable by the extractor.
<?php
[
'key' => 'This is a sample text',
'domain' => 'Admin.Some.Feature',
'parameters' => [],
];