Skip to content

Instantly share code, notes, and snippets.

@WengerK
Last active November 22, 2023 19:42
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WengerK/5c7f3df9aa5c27a95cd8a29b72b28a19 to your computer and use it in GitHub Desktop.
Save WengerK/5c7f3df9aa5c27a95cd8a29b72b28a19 to your computer and use it in GitHub Desktop.
Drupal 8 - How to translate Config API

Article Ressources - Drupal 8, How to translate Config API

This is the Gist repository for my article Drupal 8, How to translate Config API.

Be aware that this article has been wrote for the Blog of Antistatique — Web Agency in Lausanne, Switzerland. A place where I work as Full Stack Web Developer.

Feel free to read it the full article on Medium or check it out on Antistatique.

Content of this Gist :

  • SettingsForm.php : Basic Form Config
  • SettingsAdvancedForm.php : Advanced Form Config
  • my_module.settings.yml : The structure configuration file
  • my_module.settings_advanced.yml : The structure configuration file
  • my_module.schema.yml : The configuration schema which provide all config module structure
  • my_module.config_translation.yml : The configuration translation system containg all config module translations structure
  • my_module.links.task.yml : The custom tasks to show Translation tabs
my_module.settings:
title: 'My module basic settings'
base_route_name: my_module.settings
names:
- my_module.settings
my_module.settings_advanced:
title: 'My module advanced settings'
base_route_name: my_module.settings_advanced
names:
- my_module.settings_advanced
my_module.settings:
type: config_object
label: 'My module basic settings'
mapping:
title:
label: 'Title'
type: label
select:
label: 'Select'
type: string
checkbox:
label: 'Checkbox'
type: boolean
checkboxes:
label: 'Checkboxe'
type: sequence
radios:
label: 'Radios'
type: string
message:
label: 'Message'
type: text
ckeditor:
label: 'Ckeditor'
type: text_format
language:
type: string
label: 'Language code'
my_module.settings_advanced:
type: config_object
label: 'My module advanced settings'
mapping:
site:
label: 'Site'
type: mapping
mapping:
title:
label: 'Title'
type: label
content:
label: 'Content'
type: text_format
mails:
label: ‘Mails’
type: sequence
entity_reference:
label: Entity reference
type: mapping
mapping:
target_id:
type: string
label: 'Value'
langcode: en
title: ''
select: ''
checkbox: FALSE
checkboxes: { }
radios: ''
message: ''
ckeditor:
value: ''
format: 'basic_html'
site:
title: ''
content:
value: ''
format: basic_html
mails: { }
entity_reference: ''
<?php
namespace Drupal\my_module\Form;
use Drupal\Core\Form\ConfigFormBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\node\NodeStorageInterface;
/**
* My module advanced settings.
*/
class SettingsAdvancedForm extends ConfigFormBase {
/**
* Node storage.
*
* @var \Drupal\node\NodeStorageInterface
*/
protected $nodeStorage;
/**
* {@inheritdoc}
*/
public function __construct(ConfigFactoryInterface $config_factory, NodeStorageInterface $node_storage) {
parent::__construct($config_factory);
$this->nodeStorage = $node_storage;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
/* @var \Drupal\Core\Entity\EntityTypeManagerInterface */
$entityTypeManager = $container->get('entity_type.manager');
return new static(
$container->get('config.factory'),
$entityTypeManager->getStorage('node')
);
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'my_module_settings_advanced';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
'my_module.settings_advanced',
];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$settings = $this->config('my_module.settings_advanced');
// Normally when working with submitted data in $form_state['values'] the data is flattened
// and does not maintain the structure of the $form array used to generate the form.
// This behavior can be changed using the #tree property.
$form['#tree'] = TRUE;
$form['site'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => $this->t('Fieldset'),
];
$form['site']['title'] = [
'#type' => 'textfield',
'#title' => $this->t('Site - Title'),
'#default_value' => $settings->get('site')['title'],
];
$form['site']['content'] = [
'#type' => 'text_format',
'#title' => $this->t('Site - Content'),
'#format' => $settings->get('site')['content']['format'],
'#default_value' => $settings->get('site')['content']['value'],
];
$form['mails'] = [
'#type' => 'textarea',
'#title' => $this->t('List of mails'),
'#default_value' => implode('\n', $settings->get('mails')),
'#description' => $this->t('Every mail must be on a new line.'),
];
$form['nested'] = [
'#type' => 'fieldset',
'#title' => $this->t('Nested'),
];
$form['nested']['entity_reference'] = [
'#type' => 'entity_autocomplete',
'#target_type' => 'node',
'#selection_settings' => [
'target_bundles' => ['page'],
],
'#title' => $this->t('Entity Reference'),
'#default_value' => $settings->get('entity_reference') ? $this->nodeStorage->load($settings->get('entity_reference')) : NULL,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$settings = $this->configFactory->getEditable('my_module.settings_advanced');
// With the previous #tree parameter setted to TRUE
// we can access to `site` and retreive the values of both children fields
// and finaly store both fields as array of `site`.
$settings->set('site', $form_state->getValue('site'))->save();
// From string transform to array by split on new line.
$mails = explode('\n', $form_state->getValue('mails'));
$settings->set('mails', $mails)->save();
// From nested array get reference.
$entity_reference = $form_state->getValue(['nested', 'entity_reference']);
$settings->set('entity_reference', $entity_reference)->save();
}
}
<?php
namespace Drupal\my_module\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
/**
* My module basic settings.
*/
class SettingsForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'my_module_settings';
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
'my_module.settings',
];
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$settings = $this->config('my_module.settings');
$form['example'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => $this->t('Fieldset'),
];
$form['example']['title'] = [
'#type' => 'textfield',
'#default_value' => $settings->get('title'),
];
$form['fruits'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => $this->t('Fruits'),
];
$form['fruits']['select'] = [
'#type' => 'select',
'#options' => ['strawberry' => $this->t('Strawberry'), 'banana' => $this->t('Banana')],
'#default_value' => $settings->get('select'),
];
$form['home'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => $this->t('Home'),
];
$form['home']['checkbox'] = [
'#type' => 'checkbox',
'#title' => 'Light me up',
'#default_value' => $settings->get('checkbox'),
];
$form['brands'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => $this->t('Brands'),
];
$form['brands']['checkboxes'] = [
'#type' => 'checkboxes',
'#options' => ['apple' => $this->t('Apple'), 'microsoft' => $this->t('Microsoft')],
'#default_value' => $settings->get('checkboxes'),
];
$form['energy'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => $this->t('Energy'),
];
$form['energy']['radios'] = [
'#type' => 'radios',
'#options' => ['coffee' => $this->t('Coffee'), 'tea' => $this->t('Tea')],
'#default_value' => $settings->get('radios'),
];
$form['texts'] = [
'#type' => 'details',
'#open' => TRUE,
'#title' => $this->t('Texts'),
];
$form['texts']['message'] = [
'#type' => 'textarea',
'#default_value' => $settings->get('message'),
];
$form['texts']['ckeditor'] = [
'#type' => 'text_format',
'#format' => $settings->get('ckeditor')['format'],
'#default_value' => $settings->get('ckeditor')['value'],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$settings = $this->configFactory->getEditable('my_module.settings');
// Save configurations.
$settings->set('title', $form_state->getValue('title'))->save();
$settings->set('select', $form_state->getValue('select'))->save();
$settings->set('radios', $form_state->getValue('radios'))->save();
$settings->set('checkbox', $form_state->getValue('checkbox'))->save();
$settings->set('checkboxes', $form_state->getValue('checkboxes'))->save();
$settings->set('message', $form_state->getValue('message'))->save();
$settings->set('ckeditor', $form_state->getValue('ckeditor'))->save();
}
}
@pasankg
Copy link

pasankg commented Sep 23, 2020

Thank you for the gist,
Did your checkbox showed up in the translated form display ?

@philippemouchel
Copy link

philippemouchel commented Dec 16, 2021

Hello !
Thanks for this.
I've been trying it on a Drupal 9 site, and two things are not working for me:

  • I'm not able to access to the local tasks
  • when I want to translate the config through the configuration translation UI, I find the link, but it gave me a 403 (even as super-admin user 1)
    Any idea ? Maybe something has changed with D9 ?

@WengerK
Copy link
Author

WengerK commented Dec 17, 2021

I recently use that same code for a Drupal 9 project whitout issues :/

@tanmayk
Copy link

tanmayk commented Mar 30, 2022

In schema file, there is language parameter under my_module.settings. But it not under my_module.settings_advanced. What is the purpose of it? Is it required?

@tanmayk
Copy link

tanmayk commented Mar 30, 2022

@philippemouchel Did you figure it out? I am having same issues.

@tanmayk
Copy link

tanmayk commented Mar 30, 2022

@WengerK @philippemouchel No worries. I got it working after changing type of config keys from string to text. I found that string is not translatable. Thank you.

@WengerK
Copy link
Author

WengerK commented Mar 30, 2022

Happy you find out a solution @tanmayk !

Don't hestiate to comment on Medium to specify for futur readers the struggling you faced with "string" type that is not translatable ^^.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment