added event to manage javascript translations (#2104)
This commit is contained in:
64
src/Event/ThemeJavascriptTranslationsEvent.php
Normal file
64
src/Event/ThemeJavascriptTranslationsEvent.php
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<?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\Event;
|
||||||
|
|
||||||
|
use Symfony\Contracts\EventDispatcher\Event;
|
||||||
|
|
||||||
|
final class ThemeJavascriptTranslationsEvent extends Event
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Contains default translations for all views.
|
||||||
|
*
|
||||||
|
* For usage see "templates/base.html.twig" in block "javascripts".
|
||||||
|
*
|
||||||
|
* Structure
|
||||||
|
* ---------
|
||||||
|
* Javascript key: [Translation key, Translation domain]
|
||||||
|
*
|
||||||
|
* @var array<string, array<int, string>>
|
||||||
|
*/
|
||||||
|
private $translations = [
|
||||||
|
'confirm' => ['confirm', 'messages'],
|
||||||
|
'cancel' => ['cancel', 'messages'],
|
||||||
|
'today' => ['daterangepicker.today', 'daterangepicker'],
|
||||||
|
'yesterday' => ['daterangepicker.yesterday', 'daterangepicker'],
|
||||||
|
'lastWeek' => ['daterangepicker.lastWeek', 'daterangepicker'],
|
||||||
|
'thisWeek' => ['daterangepicker.thisWeek', 'daterangepicker'],
|
||||||
|
'lastMonth' => ['daterangepicker.lastMonth', 'daterangepicker'],
|
||||||
|
'thisMonth' => ['daterangepicker.thisMonth', 'daterangepicker'],
|
||||||
|
'lastYear' => ['daterangepicker.lastYear', 'daterangepicker'],
|
||||||
|
'thisYear' => ['daterangepicker.thisYear', 'daterangepicker'],
|
||||||
|
'customRange' => ['daterangepicker.customRange', 'daterangepicker'],
|
||||||
|
'timesheet.start.success' => ['timesheet.start.success', 'flashmessages'],
|
||||||
|
'timesheet.start.error' => ['timesheet.start.error', 'flashmessages'],
|
||||||
|
'timesheet.start.exceeded_limit' => ['timesheet.start.exceeded_limit', 'flashmessages'],
|
||||||
|
'timesheet.stop.success' => ['timesheet.stop.success', 'flashmessages'],
|
||||||
|
'timesheet.stop.error' => ['timesheet.stop.error', 'flashmessages'],
|
||||||
|
'action.update.success' => ['action.update.success', 'flashmessages'],
|
||||||
|
'action.update.error' => ['action.update.error', 'flashmessages'],
|
||||||
|
'action.delete.success' => ['action.delete.success', 'flashmessages'],
|
||||||
|
'action.delete.error' => ['action.delete.error', 'flashmessages'],
|
||||||
|
'confirm.delete' => ['confirm.delete', 'messages'],
|
||||||
|
'delete' => ['action.delete', 'messages'],
|
||||||
|
'login.required' => ['login_required', 'messages'],
|
||||||
|
];
|
||||||
|
|
||||||
|
public function getTranslations(): array
|
||||||
|
{
|
||||||
|
return $this->translations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTranslation(string $key, string $translationKey, string $translationDomain = 'messages'): ThemeJavascriptTranslationsEvent
|
||||||
|
{
|
||||||
|
$this->translations[$key] = [$translationKey, $translationDomain];
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ class EventExtensions extends AbstractExtension
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
new TwigFunction('trigger', [ThemeEventExtension::class, 'trigger']),
|
new TwigFunction('trigger', [ThemeEventExtension::class, 'trigger']),
|
||||||
|
new TwigFunction('javascript_translations', [ThemeEventExtension::class, 'getJavascriptTranslations']),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
namespace App\Twig\Runtime;
|
namespace App\Twig\Runtime;
|
||||||
|
|
||||||
use App\Event\ThemeEvent;
|
use App\Event\ThemeEvent;
|
||||||
|
use App\Event\ThemeJavascriptTranslationsEvent;
|
||||||
use App\Security\CurrentUser;
|
use App\Security\CurrentUser;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Twig\Extension\RuntimeExtensionInterface;
|
use Twig\Extension\RuntimeExtensionInterface;
|
||||||
@@ -46,4 +47,13 @@ final class ThemeEventExtension implements RuntimeExtensionInterface
|
|||||||
|
|
||||||
return $themeEvent;
|
return $themeEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getJavascriptTranslations(): array
|
||||||
|
{
|
||||||
|
$event = new ThemeJavascriptTranslationsEvent();
|
||||||
|
|
||||||
|
$this->eventDispatcher->dispatch($event);
|
||||||
|
|
||||||
|
return $event->getTranslations();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,29 +239,9 @@
|
|||||||
defaultColor: '{{ constant('App\\Constants::DEFAULT_COLOR') }}',
|
defaultColor: '{{ constant('App\\Constants::DEFAULT_COLOR') }}',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'confirm': '{{ 'confirm'|trans }}',
|
{% for key, translation in javascript_translations() -%}
|
||||||
'cancel': '{{ 'cancel'|trans }}',
|
'{{ key }}': '{{ translation.0|trans({}, translation.1)|escape('js') }}',
|
||||||
'today': '{{ 'daterangepicker.today'|trans({}, 'daterangepicker')|escape('js') }}',
|
{%- endfor %}
|
||||||
'yesterday': '{{ 'daterangepicker.yesterday'|trans({}, 'daterangepicker')|escape('js') }}',
|
|
||||||
'lastWeek': '{{ 'daterangepicker.lastWeek'|trans({}, 'daterangepicker')|escape('js') }}',
|
|
||||||
'thisWeek': '{{ 'daterangepicker.thisWeek'|trans({}, 'daterangepicker')|escape('js') }}',
|
|
||||||
'lastMonth': '{{ 'daterangepicker.lastMonth'|trans({}, 'daterangepicker')|escape('js') }}',
|
|
||||||
'thisMonth': '{{ 'daterangepicker.thisMonth'|trans({}, 'daterangepicker')|escape('js') }}',
|
|
||||||
'lastYear': '{{ 'daterangepicker.lastYear'|trans({}, 'daterangepicker')|escape('js') }}',
|
|
||||||
'thisYear': '{{ 'daterangepicker.thisYear'|trans({}, 'daterangepicker')|escape('js') }}',
|
|
||||||
'customRange': '{{ 'daterangepicker.customRange'|trans({}, 'daterangepicker')|escape('js') }}',
|
|
||||||
'timesheet.start.success': '{{ 'timesheet.start.success'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'timesheet.start.error': '{{ 'timesheet.start.error'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'timesheet.start.exceeded_limit': '{{ 'timesheet.start.exceeded_limit'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'timesheet.stop.success': '{{ 'timesheet.stop.success'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'timesheet.stop.error': '{{ 'timesheet.stop.error'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'action.update.success': '{{ 'action.update.success'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'action.update.error': '{{ 'action.update.error'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'action.delete.success': '{{ 'action.delete.success'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'action.delete.error': '{{ 'action.delete.error'|trans({}, 'flashmessages')|escape('js') }}',
|
|
||||||
'confirm.delete': '{{ 'confirm.delete'|trans|escape('js') }}',
|
|
||||||
'delete': '{{ 'action.delete'|trans|escape('js') }}',
|
|
||||||
'login.required': '{{ 'login_required'|trans|escape('js') }}'
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
window.kimai = loader.getKimai();
|
window.kimai = loader.getKimai();
|
||||||
|
|||||||
40
tests/Event/ThemeJavascriptTranslationsEventTest.php
Normal file
40
tests/Event/ThemeJavascriptTranslationsEventTest.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?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\Tests\Event;
|
||||||
|
|
||||||
|
use App\Event\ThemeJavascriptTranslationsEvent;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \App\Event\ThemeJavascriptTranslationsEvent
|
||||||
|
*/
|
||||||
|
class ThemeJavascriptTranslationsEventTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testDefaultValues()
|
||||||
|
{
|
||||||
|
$sut = new ThemeJavascriptTranslationsEvent();
|
||||||
|
|
||||||
|
$this->assertCount(23, $sut->getTranslations());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetterAndSetter()
|
||||||
|
{
|
||||||
|
$sut = new ThemeJavascriptTranslationsEvent();
|
||||||
|
$sut->setTranslation('foo', 'bar');
|
||||||
|
$sut->setTranslation('hello', 'world', 'testing');
|
||||||
|
|
||||||
|
$result = $sut->getTranslations();
|
||||||
|
self::assertCount(25, $result);
|
||||||
|
self::assertArrayHasKey('foo', $result);
|
||||||
|
self::assertEquals(['bar', 'messages'], $result['foo']);
|
||||||
|
self::assertArrayHasKey('hello', $result);
|
||||||
|
self::assertEquals(['world', 'testing'], $result['hello']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ class EventExtensionsTest extends TestCase
|
|||||||
|
|
||||||
public function testGetFunctions()
|
public function testGetFunctions()
|
||||||
{
|
{
|
||||||
$functions = ['trigger'];
|
$functions = ['trigger', 'javascript_translations'];
|
||||||
$sut = $this->getSut();
|
$sut = $this->getSut();
|
||||||
$twigFunctions = $sut->getFunctions();
|
$twigFunctions = $sut->getFunctions();
|
||||||
self::assertCount(\count($functions), $twigFunctions);
|
self::assertCount(\count($functions), $twigFunctions);
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class ThemeEventExtensionTest extends TestCase
|
|||||||
protected function getSut(bool $hasListener = true): ThemeEventExtension
|
protected function getSut(bool $hasListener = true): ThemeEventExtension
|
||||||
{
|
{
|
||||||
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
$dispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||||
$dispatcher->expects($this->once())->method('hasListeners')->willReturn($hasListener);
|
$dispatcher->method('hasListeners')->willReturn($hasListener);
|
||||||
$dispatcher->expects($hasListener ? $this->once() : $this->never())->method('dispatch');
|
$dispatcher->expects($hasListener ? $this->once() : $this->never())->method('dispatch');
|
||||||
|
|
||||||
$user = (new CurrentUserFactory($this))->create(new User());
|
$user = (new CurrentUserFactory($this))->create(new User());
|
||||||
@@ -45,4 +45,11 @@ class ThemeEventExtensionTest extends TestCase
|
|||||||
$event = $sut->trigger('foo', []);
|
$event = $sut->trigger('foo', []);
|
||||||
self::assertInstanceOf(ThemeEvent::class, $event);
|
self::assertInstanceOf(ThemeEvent::class, $event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testJavascriptTranslations()
|
||||||
|
{
|
||||||
|
$sut = $this->getSut();
|
||||||
|
$values = $sut->getJavascriptTranslations();
|
||||||
|
self::assertCount(23, $values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user