My problem is simple, yet I can't figure out how to solve it.
My website is multilanguage. I want the user to be able to add an article in multiple language if he wants, while requiring the inputs of his language (depending on his locale).
Problem is, with CakePHP's conventions about translation, all the inputs must end with the field's name, no matter what language. So all the fields has the same rule for the same field. I can't make one "name" required while another in another language not required.
For example, the default language's input would be:
<input type="text" name="name" required="required" maxlength="45" id="name">
And below that, another language's input for the same field:
<input type="text" name="locales[fr_CA][name]" required="required" maxlength="45" id="locales-fr-ca-name">
The "required" attribute is automatically added to both because of these rules:
$validator
->requirePresence('name', 'create')
->notEmpty('name')
->add('name', [
'length' => [
'rule' => ['minLength', 10],
'message' => 'The title needs to be at least 10 characters long.',
]
]);
Note: I have to change the locale to the default (en_US) when I save to be able to save in multiple languages + the default language (otherwise the default inputs are saved in the default table AND in the i18n table).
if ($this->request->is('post')) {
I18n::locale('en_US');
// ......
EDIT: So here's the complete piece of code when I save (IngredientsController.php)
public function add() {
$ingredient = $this->Ingredients->newEntity();
if ($this->request->is('post')) {
$ingredient = $this->Ingredients->patchEntity($ingredient, $this->request->data);
if(isset($this->request->data['locales'])) {
foreach ($this->request->data['locales'] as $lang => $data) {
$ingredient->translation($lang)->set($data, ['guard' => false]);
}
}
$locale = I18n::locale(); // At this point the locale is fr_CA (not de default)
I18n::locale('en_US'); // Change the locale to the default
if ($this->Ingredients->save($ingredient)) {
$this->Flash->success(__('The ingredient has been saved.'));
I18n::locale($locale); // Put the locale back to the user's locale
return $this->redirect(['action' => 'index']);
} else {
I18n::locale($locale);
$this->Flash->error(__('The ingredient could not be saved. Please, try again.'));
}
}
$this->set(compact('ingredient'));
$this->set('_serialize', ['ingredient']);
}
I set the default locale is the bootstrap.php
/**
* Set the default locale. This controls how dates, number and currency is
* formatted and sets the default language to use for translations.
*/
ini_set('intl.default_locale', 'en_US');
Configure::write('Config.locales', ['fr_CA']);
I determine the user's locale in the AppController.php
public function beforeFilter(Event $event)
{
$locales = Configure::read('Config.locales');
$boom = explode(',', str_replace('-', '_', $_SERVER['HTTP_ACCEPT_LANGUAGE']));
$user_lang = substr($boom[0], 0, 2);
// This piece of code is only to change the locale to fr_CA even if the user's language is just fr or fr_FR
if(in_array($user_lang, Configure::read('Config.langs'))) {
if(in_array($boom[0], $locales)) {
I18n::locale($boom[0]);
} else {
foreach ($locales as $locale) {
if(substr($locale, 0, 2) == $user_lang) {
I18n::locale($locale);
}
}
}
}
$this->set('locales', $locales);
$this->set('locale', I18n::locale());
}
So if I save while being in a different locale than the default, the same default inputs will be saved in the ingredients table AND in the i18n table in fr_CA