l10n_server-2.x-dev/l10n_community/src/Controller/L10nCommunityWelcomePageController.php
l10n_community/src/Controller/L10nCommunityWelcomePageController.php
<?php declare(strict_types=1); namespace Drupal\l10n_community\Controller; use Drupal\Component\Render\FormattableMarkup; use Drupal\Core\Cache\Cache; use Drupal\Core\Config\ConfigManagerInterface; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Url; use Drupal\l10n_community\L10nStatistics; use Drupal\l10n_groups\L10nGroupManager; use Drupal\language\Entity\ConfigurableLanguage; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RequestStack; /** * Returns responses for Localization community UI routes. */ final class L10nCommunityWelcomePageController extends ControllerBase { /** * The controller constructor. * * @param \Drupal\l10n_community\L10nStatistics $statistics * The l10n_community.statistics service. * @param \Drupal\Core\Config\ConfigManagerInterface $configManager * The config.manager service. * @param \Drupal\l10n_groups\L10nGroupManager $l10nGroupsManager * The l10n_groups.manager service. * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack * The request stack. */ public function __construct( private readonly L10nStatistics $statistics, private readonly ConfigManagerInterface $configManager, private readonly L10nGroupManager $l10nGroupsManager, private readonly RequestStack $requestStack, ) { } /** * {@inheritdoc} */ public static function create(ContainerInterface $container): self { return new L10nCommunityWelcomePageController( $container->get('l10n_community.statistics'), $container->get('config.manager'), $container->get('l10n_groups.manager'), $container->get('request_stack'), ); } /** * Title callback. * * @return \Drupal\Core\StringTranslation\TranslatableMarkup|void * Translatable markup object. * * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException */ public function title(): FormattableMarkup { $project_name = $this->configManager ->getConfigFactory() ->get('l10n_community.settings') ->get('highlighted_project'); $projects = $entities = $this->entityTypeManager() ->getStorage('l10n_server_project') ->loadByProperties( ['title' => $project_name] ); if ($project = reset($projects)) { return $this->t('Latest @project_name translation status', [ '@project_name' => $project->label(), ]); } return $this->t('Latest translation status'); } /** * Builds the response. */ public function build(): array { $config = $this->configManager->getConfigFactory()->get('l10n_community.settings'); if (!$config->get('stats_enabled')) { $build['content'] = [ '#type' => 'item', '#markup' => $this->t('Statistics for projects have been disabled.'), ]; return $build; } elseif ($project_name = $config->get('highlighted_project')) { $projects = $this->entityTypeManager() ->getStorage('l10n_server_project') ->loadByProperties( ['title' => $project_name] ); if (!$project = reset($projects)) { $build['content'] = [ '#type' => 'item', '#markup' => $this->t('Highlighted project not found.'), ]; return $build; } $releases = $this->entityTypeManager() ->getStorage('l10n_server_release') ->loadByProperties( ['pid' => $project->id()] ); $release = reset($releases); $groups = $this->l10nGroupsManager ->getGroups(); // Check for l10n_packager, for faster queries but only on latest release. if ( $this->moduleHandler()->moduleExists('l10n_packager') && $config->get('package_count') ) { [$num_source, $string_counts] = $this->statistics->getReleaseStringCount(project: $project); } else { $num_source = $this->statistics->getProjectStringCount($project); $string_counts = $this->statistics->getLanguagesStringCount($project); } $stats = $this->statistics->getProjectStringStatsByLanguage($project); $stats['users'] = $this->statistics->getLanguagesStatistics()['users']; $build['status'] = [ '#markup' => $this->t('Status based on @source source strings found in @project. Links are to untranslated strings in the release for that group.', [ '@source' => $num_source, '@project' => $project->label(), ]), ]; $table_rows = []; foreach ($this->languageManager()->getLanguages() as $langcode => $language) { if (!array_key_exists($langcode, $groups)) { // Not interested in languages attached to no group. continue; } // Need to load this again to get access to the third party settings :/. $language = ConfigurableLanguage::load($langcode); if (!$language->getThirdPartySetting('l10n_pconfig', 'formula')) { $table_rows[] = [ [ 'data' => $this->t('@language', [ '@language' => $language->getName(), ]), 'sortdata' => $this->t('@language', [ '@language' => $language->getName(), ]), 'class' => ['rowhead'], ], [ 'data' => $this->t('Uninitialized plural formula. Please set up the plural formula in <a href="@language-config">the language configuration</a> or alternatively <a href="@import-url">import a valid interface translation</a> for Drupal in this language.', [ '@import-url' => Url::fromUri('internal:/admin/structure/translate/import')->toString(), '@language-config' => Url::fromUri('internal:/admin/config/regional/language/edit/' . $language->getId())->toString(), ]), 'sortdata' => '', 'class' => ['error'], ], [ 'data' => 0, 'sortdata' => 0, ], ]; } else { $progress = [ 'data' => [ '#theme' => 'l10n_community_progress_columns', '#sum' => $stats[$langcode]['count'] ?? 0, '#translated' => $stats[$langcode]['translations'] ?? 0, '#has_suggestion' => $stats[$langcode]['suggestions'] ?? 0, ], ]; $table_rows[] = [ [ 'data' => new FormattableMarkup('<a href=":link">@name</a>', [ ':link' => Url::fromRoute('l10n_community.language.translate.translate', [ 'group' => $groups[$langcode]->id(), ], [ 'query' => [ 'project' => $project->getUri(), 'status' => 1, 'release' => ($release ? $release->id() : 'all'), ], ])->toString(), '@name' => $language->getName(), ]), 'sortdata' => $this->t('@language', [ '@language' => $language->getName(), ])->__toString(), 'class' => ['rowhead'], ], [ 'data' => $progress, 'sortdata' => ($num_source == 0 ? 0 : round(($string_counts[$langcode]['translations'] ?? 0) / $num_source * 100, 2)), ], [ 'data' => (int) (array_key_exists($langcode, $stats['users'])) ? $stats['users'][$langcode]['count'] : 0, 'sortdata' => (int) (array_key_exists($langcode, $stats['users'])) ? $stats['users'][$langcode]['count'] : 0, ], ]; } } if ( !empty($this->requestStack->getCurrentRequest()->get('sort')) && !empty($this->requestStack->getCurrentRequest()->get('order')) ) { usort($table_rows, static::class . '::sortByColumns'); } $header = [ [ 'data' => $this->t('Language'), 'field' => 'language', 'class' => ['rowhead'], ], [ 'data' => $this->t('@project progress', [ '@project' => $project->label(), ]), 'field' => 'progress', 'sort' => 'desc', ], [ 'data' => $this->t('Contributors'), 'field' => 'contributors', ], ]; $build['content'] = [ '#type' => 'table', '#header' => $header, '#rows' => $table_rows, '#attributes' => [ 'class' => [ 'l10n-community-overview l10n-community-highlighted', ], ], ]; $build['#attached']['library'][] = 'l10n_community/tables'; $project_count = $this->entityTypeManager() ->getStorage('l10n_server_project') ->getQuery() ->accessCheck(TRUE) ->condition('status', 1) ->count() ->execute(); if ($project_count > 1) { $build['count'] = [ '#type' => 'html_tag', '#tag' => 'p', '#value' => $this->formatPlural( $project_count, '@project is just one of the <a href="@projects">@count projects translated on this server</a>. Check them out.', '@project is just one of the <a href="@projects">@count projects translated on this server</a>. Check them out.', [ '@project' => $project->label(), '@projects' => Url::fromUri('internal:/translate/projects')->toString(), ] ), ]; } return $build; } $build['content'] = [ '#type' => 'item', '#markup' => $this->t('No highlighted project set.'), '#cache' => [ 'max-age' => Cache::PERMANENT, ], ]; return $build; } /** * Order listing table by columns. */ public static function sortByColumns(array $a, array $b): int { $requestStack = \Drupal::service('request_stack'); $sortkey = ( $requestStack->getCurrentRequest()->get('order') === t('Language')->__toString() ? 0 : ($requestStack->getCurrentRequest()->get('order') === t('Contributors')->__toString() ? 2 : 1 ) ); if ($a[$sortkey]['sortdata'] === $b[$sortkey]['sortdata']) { return 0; } return (($a[$sortkey]['sortdata'] < $b[$sortkey]['sortdata']) ? -1 : 1) * ($requestStack->getCurrentRequest()->get('sort') === 'asc' ? 1 : -1); } }