HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /home/timetracker.panomity.com/src/Command/RegenerateLocalesCommand.php
<?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\Command;

use App\Configuration\LocaleService;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Intl\Locales;

/**
 * Command used to create the locale definition.
 *
 * We do NOT calculate that on every system again, because we want to make sure that we have the same
 * settings in every environment. Some environments (e.g. Github-Actions) have diverging settings from
 * the local system.
 *
 * @codeCoverageIgnore
 */
#[AsCommand(name: 'kimai:reset:locales')]
final class RegenerateLocalesCommand extends Command
{
    private string $defaultDate = 'dd.MM.y';
    private string $defaultTime = 'HH:mm';
    private array $rtlLocales = [
        'ar' => true,
        'fa' => true,
        'he' => true,
    ];

    public function __construct(private LocaleService $localeService, private string $projectDirectory, private string $kernelEnvironment)
    {
        parent::__construct();
    }

    public function isEnabled(): bool
    {
        return $this->kernelEnvironment !== 'prod';
    }

    protected function configure(): void
    {
        $this->setDescription('Regenerate the locale definition file');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $locales = $this->localeService->getAllLocales();

        // detect all registered locales and allow to choose them as well, so people get to
        // choose the language for translation with the correct format of their location
        /*
        $secondLevel = [];
        foreach (Locales::getLocales() as $locale) {
            if (substr_count($locale, '_') === 1) {
                $baseLocale = substr($locale, 0, strpos($locale, '_'));
                if (in_array($baseLocale, $locales)) {
                    $subLocale = substr($locale, strpos($locale, '_') + 1);
                    if (!is_numeric($subLocale)) {
                        $secondLevel[] = $locale;
                    }
                }
            }
        }
        $locales = array_merge($locales, $secondLevel);
        */

        $appLocales = [];
        $defaults = [
            'date' => $this->defaultDate,
            'time' => $this->defaultTime,
            'rtl' => false,
        ];

        // make sure all allowed locales are registered
        foreach ($locales as $locale) {
            if (!Locales::exists($locale)) {
                continue;
            }

            $appLocales[$locale] = $defaults;
        }

        // make sure all keys are registered for every locale
        foreach ($appLocales as $locale => $settings) {
            // these are completely new since v2
            // calculate everything with IntlFormatter
            $shortDate = new \IntlDateFormatter($locale, \IntlDateFormatter::SHORT, \IntlDateFormatter::NONE);
            $shortTime = new \IntlDateFormatter($locale, \IntlDateFormatter::NONE, \IntlDateFormatter::SHORT);

            $settings['date'] = $shortDate->getPattern();
            $settings['time'] = $shortTime->getPattern();

            // make sure that sub-locales of a RTL language are also flagged as RTL
            $rtlLocale = $locale;
            if (substr_count($rtlLocale, '_') === 1) {
                $rtlLocale = substr($rtlLocale, 0, strpos($rtlLocale, '_'));
            }

            if (\array_key_exists($rtlLocale, $this->rtlLocales)) {
                $settings['rtl'] = $this->rtlLocales[$rtlLocale];
            }

            // pre-fill all formats with the default locale settings
            $appLocales[$locale] = $settings;
        }

        ksort($appLocales);

        $filename = 'config/locales.php';
        $targetFile = $this->projectDirectory . DIRECTORY_SEPARATOR . $filename;

        $content = '<?php return ' . var_export($appLocales, true) . ';';
        $content = str_replace('array (', '[', $content);
        $content = str_replace(')', ']', $content);

        file_put_contents($targetFile, $content);

        $io->success('Created new locale definition at: ' . $filename);

        return Command::SUCCESS;
    }
}