Skip to content

Commit

Permalink
feature #32388 [Form] Allow to translate each language into its langu…
Browse files Browse the repository at this point in the history
…age in LanguageType (javiereguiluz)

This PR was squashed before being merged into the 5.1-dev branch (closes #32388).

Discussion
----------

[Form] Allow to translate each language into its language in LanguageType

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | #31562
| License       | MIT
| Doc PR        | I'll do it if this is approved

This would allow to set this option:

```php
->add('language', LanguageType::class, [
    'choice_self_translation' => true,
])
```

To display each language translated into its own language:

![image](https://user-images.githubusercontent.com/73419/60709908-cdf29b80-9f11-11e9-83c8-8ee939c0de3a.png)

@ro0NL if this proposal is approved, could you please tell me why I must `try ... catch` with `\Exception`?

* First, I need the try..catch because of a special language with the code "root" which triggers exceptions (*The resource bundle "symfony-code/src/Symfony/Component/Intl/Resources/data/languages/root.json" does not exist*)
* Second, I must catch \Exception because when I try to catch the exact exception (`Symfony\Component\Intl\Exception\ResourceBundleNotFoundException`) the exception is not caught. Why?

Commits
-------

138200c [Form] Allow to translate each language into its language in LanguageType
  • Loading branch information
fabpot committed Dec 3, 2019
2 parents e0f6cdb + 138200c commit 9097230
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 3 deletions.
32 changes: 29 additions & 3 deletions src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader;
use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Intl\Exception\MissingResourceException;
use Symfony\Component\Intl\Languages;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
Expand All @@ -27,19 +29,43 @@ public function configureOptions(OptionsResolver $resolver)
$resolver->setDefaults([
'choice_loader' => function (Options $options) {
$choiceTranslationLocale = $options['choice_translation_locale'];
$alpha3 = $options['alpha3'];
$useAlpha3Codes = $options['alpha3'];
$choiceSelfTranslation = $options['choice_self_translation'];

return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $alpha3) {
return array_flip($alpha3 ? Languages::getAlpha3Names($choiceTranslationLocale) : Languages::getNames($choiceTranslationLocale));
return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale, $useAlpha3Codes, $choiceSelfTranslation) {
if (true === $choiceSelfTranslation) {
foreach (Languages::getLanguageCodes() as $alpha2Code) {
try {
$languageCode = $useAlpha3Codes ? Languages::getAlpha3Code($alpha2Code) : $alpha2Code;
$languagesList[$languageCode] = Languages::getName($alpha2Code, $alpha2Code);
} catch (MissingResourceException $e) {
// ignore errors like "Couldn't read the indices for the locale 'meta'"
}
}
} else {
$languagesList = $useAlpha3Codes ? Languages::getAlpha3Names($choiceTranslationLocale) : Languages::getNames($choiceTranslationLocale);
}

return array_flip($languagesList);
});
},
'choice_translation_domain' => false,
'choice_translation_locale' => null,
'alpha3' => false,
'choice_self_translation' => false,
]);

$resolver->setAllowedTypes('choice_self_translation', ['bool']);
$resolver->setAllowedTypes('choice_translation_locale', ['null', 'string']);
$resolver->setAllowedTypes('alpha3', 'bool');

$resolver->setNormalizer('choice_self_translation', function (Options $options, $value) {
if (true === $value && $options['choice_translation_locale']) {
throw new LogicException('Cannot use the "choice_self_translation" and "choice_translation_locale" options at the same time. Remove one of them.');
}

return $value;
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Symfony\Component\Form\Tests\Extension\Core\Type;

use Symfony\Component\Form\ChoiceList\View\ChoiceView;
use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Intl\Util\IntlTestHelper;

class LanguageTypeTest extends BaseTypeTest
Expand Down Expand Up @@ -86,6 +87,52 @@ public function testChoiceTranslationLocaleAndAlpha3Option()
$this->assertNotContainsEquals(new ChoiceView('my', 'my', 'бірманська'), $choices);
}

/**
* @requires extension intl
*/
public function testChoiceSelfTranslationOption()
{
$choices = $this->factory
->create(static::TESTED_TYPE, null, [
'choice_self_translation' => true,
])
->createView()->vars['choices'];

$this->assertContainsEquals(new ChoiceView('cs', 'cs', 'čeština'), $choices);
$this->assertContainsEquals(new ChoiceView('es', 'es', 'español'), $choices);
$this->assertContainsEquals(new ChoiceView('fr', 'fr', 'français'), $choices);
$this->assertContainsEquals(new ChoiceView('ta', 'ta', 'தமிழ்'), $choices);
$this->assertContainsEquals(new ChoiceView('uk', 'uk', 'українська'), $choices);
$this->assertContainsEquals(new ChoiceView('yi', 'yi', 'ייִדיש'), $choices);
$this->assertContainsEquals(new ChoiceView('zh', 'zh', '中文'), $choices);
}

/**
* @requires extension intl
*/
public function testChoiceSelfTranslationAndAlpha3Options()
{
$choices = $this->factory
->create(static::TESTED_TYPE, null, [
'alpha3' => true,
'choice_self_translation' => true,
])
->createView()->vars['choices'];

$this->assertContainsEquals(new ChoiceView('spa', 'spa', 'español'), $choices, '', false, false);
$this->assertContainsEquals(new ChoiceView('yid', 'yid', 'ייִדיש'), $choices, '', false, false);
}

public function testSelfTranslationNotAllowedWithChoiceTranslation()
{
$this->expectException(LogicException::class);

$this->factory->create(static::TESTED_TYPE, null, [
'choice_translation_locale' => 'es',
'choice_self_translation' => true,
]);
}

public function testMultipleLanguagesIsNotIncluded()
{
$choices = $this->factory->create(static::TESTED_TYPE, 'language')
Expand Down

0 comments on commit 9097230

Please sign in to comment.