Split user language (UI translation) from locale (formatted values) (#4595)
This commit is contained in:
@@ -12,10 +12,9 @@ namespace App\Form\Helper;
|
||||
use App\Configuration\LocaleService;
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Entity\Project;
|
||||
use Symfony\Contracts\Translation\LocaleAwareInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
final class ProjectHelper implements LocaleAwareInterface
|
||||
final class ProjectHelper
|
||||
{
|
||||
public const PATTERN_NAME = '{name}';
|
||||
public const PATTERN_COMMENT = '{comment}';
|
||||
@@ -33,7 +32,11 @@ final class ProjectHelper implements LocaleAwareInterface
|
||||
private bool $showEnd = false;
|
||||
private ?string $locale = null;
|
||||
|
||||
public function __construct(private SystemConfiguration $configuration, private LocaleService $localeService, private TranslatorInterface $translator)
|
||||
public function __construct(
|
||||
private readonly SystemConfiguration $configuration,
|
||||
private readonly LocaleService $localeService,
|
||||
private readonly TranslatorInterface $translator
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -42,7 +45,7 @@ final class ProjectHelper implements LocaleAwareInterface
|
||||
return $this->locale ?? \Locale::getDefault();
|
||||
}
|
||||
|
||||
public function setLocale(string $locale): void
|
||||
public function setLocale(?string $locale): void
|
||||
{
|
||||
$this->locale = $locale;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use App\Configuration\LocaleService;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Intl\Locales;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
@@ -20,21 +21,32 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
*/
|
||||
final class LanguageType extends AbstractType
|
||||
{
|
||||
public function __construct(private LocaleService $localeService)
|
||||
public function __construct(private readonly LocaleService $localeService)
|
||||
{
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$choices = [];
|
||||
foreach ($this->localeService->getAllLocales() as $key) {
|
||||
$name = ucfirst(Locales::getName($key, $key));
|
||||
$choices[$name] = $key;
|
||||
}
|
||||
$resolver->setDefault('choices', function (Options $options) {
|
||||
$choices = [];
|
||||
|
||||
if ($options['translated_only'] === true) {
|
||||
$locales = $this->localeService->getTranslatedLocales();
|
||||
} else {
|
||||
$locales = $this->localeService->getAllLocales();
|
||||
}
|
||||
|
||||
foreach ($locales as $key) {
|
||||
$name = ucfirst(Locales::getName($key, $key));
|
||||
$choices[$name] = $key;
|
||||
}
|
||||
|
||||
return $choices;
|
||||
});
|
||||
|
||||
$resolver->setDefaults([
|
||||
'choices' => $choices,
|
||||
'label' => 'language',
|
||||
'translated_only' => false,
|
||||
'choice_translation_domain' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ use Symfony\Component\Form\CallbackTransformer;
|
||||
use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
final class TimePickerType extends AbstractType
|
||||
@@ -40,6 +42,11 @@ final class TimePickerType extends AbstractType
|
||||
]);
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form, array $options): void
|
||||
{
|
||||
$view->vars['format'] = $options['format'];
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder->addModelTransformer(
|
||||
|
||||
@@ -9,30 +9,43 @@
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use App\Configuration\LocaleService;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\CallbackTransformer;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Custom form field type to select the user language.
|
||||
* Custom form field type to select the user language, which is used to translate the UI.
|
||||
* @extends AbstractType<string>
|
||||
*/
|
||||
final class UserLanguageType extends AbstractType
|
||||
{
|
||||
public function __construct(private UrlGeneratorInterface $router, private TranslatorInterface $translator)
|
||||
public function __construct(private readonly LocaleService $localeService)
|
||||
{
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder->addModelTransformer(new CallbackTransformer(
|
||||
function ($value) {
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->localeService->getNearestTranslationLocale($value);
|
||||
},
|
||||
function ($value) {
|
||||
return $value;
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$route = $this->router->generate('help_locales');
|
||||
$message = $this->translator->trans('user.language.help');
|
||||
$moreLink = $this->translator->trans('help_locales');
|
||||
|
||||
$resolver->setDefaults([
|
||||
'help_html' => true,
|
||||
'help' => sprintf('%2$s <a href="%1$s" target="help_locales">%3$s</a>', $route, $message, $moreLink)
|
||||
'label' => 'language',
|
||||
'translated_only' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
47
src/Form/Type/UserLocaleType.php
Normal file
47
src/Form/Type/UserLocaleType.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Custom form field type to select the user locale, which is used to format date/time/money/number values.
|
||||
*
|
||||
* @extends AbstractType<string>
|
||||
*/
|
||||
final class UserLocaleType extends AbstractType
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UrlGeneratorInterface $router,
|
||||
private readonly TranslatorInterface $translator
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$route = $this->router->generate('help_locales');
|
||||
$moreLink = $this->translator->trans('help_locales');
|
||||
|
||||
$resolver->setDefaults([
|
||||
'label' => 'locale',
|
||||
'help_html' => true,
|
||||
'help' => sprintf('<a href="%1$s" target="help_locales">%2$s</a>', $route, $moreLink)
|
||||
]);
|
||||
}
|
||||
|
||||
public function getParent(): string
|
||||
{
|
||||
return LanguageType::class;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ use App\Form\Type\AvatarType;
|
||||
use App\Form\Type\MailType;
|
||||
use App\Form\Type\TimezoneType;
|
||||
use App\Form\Type\UserLanguageType;
|
||||
use App\Form\Type\UserLocaleType;
|
||||
use App\Form\Type\UserType;
|
||||
use App\Form\Type\YesNoType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
@@ -80,6 +81,10 @@ class UserEditType extends AbstractType
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$builder->add('locale', UserLocaleType::class, [
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$builder->add('timezone', TimezoneType::class, [
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user