AtroCore provides a powerful and easy-to-use localization system to support multiple languages. All translation data is stored in JSON format within the Resources/i18n
folder of the core or any custom modules.
Each language has its own folder named after the language code (e.g., en_US
for US English). These folders contain two types of files:
Global.json
: Contains translations for global elements like entity names and universal labels.{EntityName}.json
: Provides specific translations for a given entity, includingfields
,options
,labels
,messages
,tooltips
, andexceptions
.
Example: en_US/Example.json
{
"fields": {
"type": "Type"
},
"options": {
"type": {
"simple": "Simple",
"composite": "Composite"
}
},
"labels": {
"myLabel": "My label"
},
"messages": {
"myMessage": "My message"
},
"tooltips":{
"type": "Use to define the type of example"
},
"exceptions": {
"errorWhenCreating": "There was an error when creating"
}
}
Translations from the core and all modules are loaded and merged during system initialization. Similar to Metadata, any module can add or update translations for any entity.
Regenerating System Translations
System translations are managed through a command-line utility. The translation data is not sourced directly from JSON files but is compiled into a database entity for performance and consistency.
Command:
php console.php refresh translations
Process:
The refresh translations
command executes a process that:
- Loads: All translation data from the JSON files across all modules.
- Merges: The loaded data into a single, comprehensive translation set.
- Persists: This merged data into the
Translation
ReferenceData
entity.
This approach ensures the application has a single source of truth for all localization strings, which is the Translation
entity.
Learn more about the
ReferenceData
entity type in the Entities section.
Accessing Translations
Use the language
service from the container to access translations.
/** @var Espo\Core\Utils\Language $language */
$language = $container->get('language');
$localizeField = $language->translate($tranlationKey, $categorie, $scope);
$tranlationKey
is a JSON key from within a translation file.$category
is the top-level key (fields
,labels
, etc.).$scope
is the entity name, orGlobal
by default.
For the particular of translating options for static list fields use :
/** @var Espo\Core\Utils\Language $language */
$language = $container->get('language');
$localizeOption= $language->translateOption($optionCode, $field, $scope);
$option
is a JSON key from within a translation file.$field
static list field of the entity$scope
.$scope
is the entity name
The system automatically detects the user's language or uses a fallback language from the configuration.
Example Usage:
Assuming the user's language is English (en_US
):
/** @var Espo\Core\Utils\Language $language */
$language = $container->get('language');
$localizeField = $language->translate('type', 'fields', 'Example');
// $localizeField is "Type"
$localizeLabel = $language->translate('myLabel', 'labels', 'Example');
// $localizeField is "My label"
$localizeOption = $language->translateOption('simple', 'type', 'Example');
// $localizeField is Simple
To set a specific language, use the setLangage
method:
/** @var Espo\Core\Utils\Language $language */
$language = $container->get('language');
$language->setLangage('de_DE'); // Sets the language to German
//or set the locale directly by using $language->setLocale($localeId)
$localizeText = $language->translate('type', 'fields', 'Example');
In the frontend, the translate
method is also available in any view:
let localizeField = this.translate('type', 'fields', 'Example');
// localizeField is "Type"
Updating Translation in code
As we have seen above, the translations is persisted using the entity Translation
.
The container service Language convenient means to make modification like:
- Localize a new key
- Update an existing localization
- Delete a localization **How it works***
/** @var Espo\Core\Utils\Language $language */
$language = $container->get('language');
// create or update (if it exists)
$language->set($scope, $category, $key, $newValue);
// delete
$language->delete($scope, $category, $key);
// create or update and option's translation (if it exists)
$language->setOption($scope, $field, $optionName, $newValue);
// delete an option's translation
$language->deleteOption($scope, $field, $optionName);
// apply change
$language->save();
Translation modified this way will not change after refreshing translation regeneration. To modify translation in the UI go to Administration / Translation
Example:
/** @var Espo\Core\Utils\Language $language */
$language = $container->get('language');
$language->set($entity->get('entityId'), 'tooltips', $entity->get('code'), $entity->get('tooltipText'));
Dynamic extension via listener
Check the section Extending with listener for more information.