Browse Source

Introduit l'i18n et la l10n fr/en

master
vincent 20 hours ago
parent
commit
8a3de6adaa
11 changed files with 124 additions and 23 deletions
  1. +9
    -0
      README.md
  2. +1
    -0
      composer.json
  3. +13
    -13
      composer.lock
  4. +2
    -2
      config/packages/translation.yaml
  5. +10
    -3
      src/Controller/BadgeController.php
  6. +16
    -3
      src/Controller/HomeController.php
  7. +38
    -0
      src/EventSubscriber/LocaleSubscriber.php
  8. +7
    -0
      templates/_header.html.twig
  9. +2
    -2
      templates/home/index.html.twig
  10. +13
    -0
      translations/messages.en.yaml
  11. +13
    -0
      translations/messages.fr.yaml

+ 9
- 0
README.md View File

@ -71,4 +71,13 @@ les variables :
l’adresse web de son instance suffixée du chemin `/osm/callback` et comme
autorisation, uniquement « Lire les préférences de l’utilisateur »)
# TODO
* API pour interactions automatisées
* nouveaux outils :
- découpage d'une zone géographique en carrés d'une surface donnée
- depuis un gros GeoJSON faire autant de tâches que de *features*
- faire autant de tâches que d'éléments Osmose d'un certain type sur une emprise donnée
- pouvoir fédérer plusieurs instances (avec de l'ActivityPub ?)

+ 1
- 0
composer.json View File

@ -34,6 +34,7 @@
"symfony/runtime": "7.3.*",
"symfony/security-bundle": "7.3.*",
"symfony/stimulus-bundle": "^2.18",
"symfony/translation": "7.3.*",
"symfony/twig-bundle": "7.3.*",
"symfony/validator": "7.3.*",
"symfony/workflow": "7.3.*",


+ 13
- 13
composer.lock View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "a2a5c548491ca262277ef9a55c872ad1",
"content-hash": "d035db9a327bfae49b87a5a0e08c5198",
"packages": [
{
"name": "behat/transliterator",
@ -4642,16 +4642,16 @@
},
{
"name": "symfony/flex",
"version": "v2.8.0",
"version": "v2.8.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/flex.git",
"reference": "68cdcde0b7e36b008a08bcf3709c07a20e757a29"
"reference": "423c36e369361003dc31ef11c5f15fb589e52c01"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/flex/zipball/68cdcde0b7e36b008a08bcf3709c07a20e757a29",
"reference": "68cdcde0b7e36b008a08bcf3709c07a20e757a29",
"url": "https://api.github.com/repos/symfony/flex/zipball/423c36e369361003dc31ef11c5f15fb589e52c01",
"reference": "423c36e369361003dc31ef11c5f15fb589e52c01",
"shasum": ""
},
"require": {
@ -4690,7 +4690,7 @@
"description": "Composer plugin for Symfony",
"support": {
"issues": "https://github.com/symfony/flex/issues",
"source": "https://github.com/symfony/flex/tree/v2.8.0"
"source": "https://github.com/symfony/flex/tree/v2.8.1"
},
"funding": [
{
@ -4706,7 +4706,7 @@
"type": "tidelift"
}
],
"time": "2025-07-04T06:30:46+00:00"
"time": "2025-07-05T07:45:19+00:00"
},
{
"name": "symfony/form",
@ -8974,16 +8974,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.76.0",
"version": "v3.81.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "0e3c484cef0ae9314b0f85986a36296087432c40"
"reference": "e00a39c729aced6c3771b9530c6e58c2efa87592"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/0e3c484cef0ae9314b0f85986a36296087432c40",
"reference": "0e3c484cef0ae9314b0f85986a36296087432c40",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/e00a39c729aced6c3771b9530c6e58c2efa87592",
"reference": "e00a39c729aced6c3771b9530c6e58c2efa87592",
"shasum": ""
},
"require": {
@ -9067,7 +9067,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.76.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.81.0"
},
"funding": [
{
@ -9075,7 +9075,7 @@
"type": "github"
}
],
"time": "2025-06-30T14:15:06+00:00"
"time": "2025-07-07T15:27:54+00:00"
},
{
"name": "nikic/php-parser",


+ 2
- 2
config/packages/translation.yaml View File

@ -1,7 +1,7 @@
framework:
default_locale: en
default_locale: fr
translator:
default_path: '%kernel.project_dir%/translations'
fallbacks:
- en
- fr
providers:

+ 10
- 3
src/Controller/BadgeController.php View File

@ -10,21 +10,28 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
#[Route('/badge')]
class BadgeController extends AbstractController
{
#[Route('/project-status/{projectSlug}/{status}', name: 'app_badge_project_status')]
public function index(EntityManagerInterface $entityManager, TaskLifecycleManager $taskLifecycleManager, string $projectSlug, string $status): Response
public function index(
EntityManagerInterface $entityManager,
TaskLifecycleManager $taskLifecycleManager,
TranslatorInterface $translator,
string $projectSlug,
string $status
): Response
{
$project = $entityManager->getRepository(Project::class)->findOneBySlug($projectSlug);
if (!$project) {
throw new NotFoundHttpException('Project not found');
throw new NotFoundHttpException($translator->trans('exception.project_not_found'));
}
$stats = $taskLifecycleManager->getProjectStats($project);
if (empty($stats) || !isset($stats[$status])) {
throw new NotFoundHttpException('Status not found');
throw new NotFoundHttpException($translator->trans('exception.status_not_found'));
}
$stats = $stats[$status];


+ 16
- 3
src/Controller/HomeController.php View File

@ -10,6 +10,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
class HomeController extends AbstractController
{
@ -24,6 +25,18 @@ class HomeController extends AbstractController
]);
}
#[Route('/{locale}', name: 'app_locale', requirements: ['locale' => '(fr|en)'])]
public function changeLocale(Request $request, $locale): Response
{
$request->getSession()->set('_locale', $locale);
if ($request->headers->has('Referer')) {
return $this->redirect($request->headers->get('Referer'));
} else {
return $this->redirect('app_home');
}
}
// Page d’erreur
public function error(Request $request, $exception, $logger = null): Response
{
@ -57,17 +70,17 @@ class HomeController extends AbstractController
// L’oauth OSM aboutit ici
#[Route('/osm/callback', name: 'app_osm_callback')]
public function osmCallback(Request $request, ClientRegistry $clientRegistry): Response
public function osmCallback(Request $request, ClientRegistry $clientRegistry, TranslatorInterface $translator): Response
{
$client = $clientRegistry->getClient('openstreetmap');
if ($request->query->has('error')) {
$this->addFlash('danger', sprintf(
'Échec de l’authentification (%s)',
$translator->trans('alert.auth_failure').' (%s)',
$request->query->has('error_description') ? $request->query->get('error_description') : $request->query->get('error')
));
} else {
$this->addFlash('success', 'Authentification OSM réussie !');
$this->addFlash('success', $translator->trans('alert.auth_success'));
}
$session = $request->getSession();


+ 38
- 0
src/EventSubscriber/LocaleSubscriber.php View File

@ -0,0 +1,38 @@
<?php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class LocaleSubscriber implements EventSubscriberInterface
{
public function __construct(
private string $defaultLocale = 'fr',
) {
}
public function onKernelRequest(RequestEvent $event): void
{
$request = $event->getRequest();
if (!$request->hasPreviousSession()) {
return;
}
// try to see if the locale has been set as a _locale routing parameter
if ($locale = $request->attributes->get('_locale')) {
$request->getSession()->set('_locale', $locale);
} else {
// if no explicit locale has been set on this request, use one from the session
$request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
}
}
public static function getSubscribedEvents(): array
{
return [
// must be registered before (i.e. with a higher priority than) the default Locale listener
KernelEvents::REQUEST => [['onKernelRequest', 20]],
];
}
}

+ 7
- 0
templates/_header.html.twig View File

@ -55,5 +55,12 @@
</ul>
</div>
</div>
<div class="d-flex">
<div class="btn-group me-3">
{% for locale in ['fr', 'en'] %}
<a href="{{ path('app_locale', {'locale': locale}) }}" class="btn btn-light{% if app.request.locale == locale %} active{% endif %}">{{ locale }}</a>
{% endfor %}
</div>
</div>
</nav>
</header>

+ 2
- 2
templates/home/index.html.twig View File

@ -4,7 +4,7 @@
<div class="px-4 py-5 my-5 text-center">
<h1 class="display-5 fw-bold text-body-emphasis">{{ long_title }}</h1>
<div class="col-lg-6 mx-auto">
<p class="lead mb-4">Gère les tâches, même avec des nœuds (ou pas).</p>
<p class="lead mb-4">{{ 'text.home1'|trans }}</p>
<p class="lead mb-4">L’idée c’est d’avoir un petit outil collaboratif simple et facile à administrer/utiliser pour mapper des trucs de façon coordonnée à un endroit.</p>
<p class="text-muted mb-4">Si d’aventure vous souhaitez contacter le développeur, merci d’écrire à <a href="mailto:v+osm@caboulot.org?subject={{ short_title }}">v+osm@caboulot.org</a></p>
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
@ -17,7 +17,7 @@
<section class="container">
<div class="row">
<div class="col mb-3">
<h2>Projets populaires</h2>
<h2>{{ 'title.popular_projects'|trans }}</h2>
</div>
</div>
<div class="row">


+ 13
- 0
translations/messages.en.yaml View File

@ -0,0 +1,13 @@
exception:
project_not_found: 'Project not found'
status_not_found: 'Status not found'
alert:
auth_failure: 'Authentification failed'
auth_success: 'Authentification successfull !'
title:
popular_projects: 'Popular projects'
text:
home1: 'Handle tasks, even with nodes (or not).'

+ 13
- 0
translations/messages.fr.yaml View File

@ -0,0 +1,13 @@
exception:
project_not_found: 'Projet introuvable'
status_not_found: 'État introuvable'
alert:
auth_failure: 'Échec de l’authentification'
auth_success: 'Authentification OSM réussie !'
title:
popular_projects: 'Projets populaires'
text:
home1: 'Gère les tâches, même avec des nœuds (ou pas).'

Loading…
Cancel
Save