translate time-tracking in login screen and browser title (#738)

This commit is contained in:
Kevin Papst
2019-04-30 17:52:19 +02:00
committed by GitHub
parent b35022d161
commit b865add1b3
29 changed files with 307 additions and 125 deletions

View File

@@ -69,13 +69,13 @@ class MenuSubscriber implements EventSubscriberInterface
if ($auth->isGranted('view_own_timesheet')) { if ($auth->isGranted('view_own_timesheet')) {
$menu->addItem( $menu->addItem(
new MenuItemModel('timesheet', 'menu.timesheet', 'timesheet', [], 'far fa-clock') new MenuItemModel('timesheet', 'menu.timesheet', 'timesheet', [], 'fas fa-clock')
); );
} }
if ($auth->isGranted('view_invoice')) { if ($auth->isGranted('view_invoice')) {
$menu->addItem( $menu->addItem(
new MenuItemModel('invoice', 'menu.invoice', 'invoice', [], 'far fa-file-alt') new MenuItemModel('invoice', 'menu.invoice', 'invoice', [], 'fas fa-file-invoice')
); );
} }

View File

@@ -0,0 +1,98 @@
<?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\Twig;
use Symfony\Component\HttpFoundation\RequestStack;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class DatatableExtensions extends AbstractExtension
{
/**
* @var RequestStack
*/
protected $requestStack;
/**
* @var array
*/
protected $cookies = [];
/**
* @param RequestStack $requestStack
*/
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return [
new TwigFunction('is_visible_column', [$this, 'isColumnVisible']),
new TwigFunction('is_datatable_configured', [$this, 'isDatatableConfigured']),
];
}
/**
* @param string $dataTable
* @return bool
*/
public function isDatatableConfigured(string $dataTable)
{
$cookie = $this->getVisibilityCookieName($dataTable);
return $this->requestStack->getCurrentRequest()->cookies->has($cookie);
}
/**
* @param string $dataTable
* @return string
*/
protected function getVisibilityCookieName(string $dataTable)
{
return $dataTable . '_visibility';
}
/**
* This is only for datatables, do not use it outside this context.
*
* @param string $dataTable
* @param string $column
* @return bool
*/
public function isColumnVisible(string $dataTable, string $column)
{
// name handling is spread between here and datatables.html.twig (data_table_column_modal)
$cookie = $this->getVisibilityCookieName($dataTable);
if (!isset($this->cookies[$cookie])) {
$visibility = false;
if ($this->requestStack->getCurrentRequest()->cookies->has($cookie)) {
$visibility = json_decode($this->requestStack->getCurrentRequest()->cookies->get($cookie), true);
}
$this->cookies[$cookie] = $visibility;
}
$values = $this->cookies[$cookie];
if (empty($values) || !is_array($values)) {
return true;
}
if (isset($values[$column]) && $values[$column] === false) {
return false;
}
return true;
}
}

View File

@@ -14,7 +14,6 @@ use App\Entity\Timesheet;
use App\Utils\Duration; use App\Utils\Duration;
use App\Utils\LocaleSettings; use App\Utils\LocaleSettings;
use NumberFormatter; use NumberFormatter;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Intl;
use Twig\Extension\AbstractExtension; use Twig\Extension\AbstractExtension;
use Twig\TwigFilter; use Twig\TwigFilter;
@@ -29,17 +28,14 @@ class Extensions extends AbstractExtension
* @var LocaleSettings * @var LocaleSettings
*/ */
protected $localeSettings; protected $localeSettings;
/** /**
* @var string * @var string
*/ */
protected $locale; protected $locale;
/** /**
* @var Duration * @var Duration
*/ */
protected $durationFormatter; protected $durationFormatter;
/** /**
* @var NumberFormatter * @var NumberFormatter
*/ */
@@ -49,16 +45,6 @@ class Extensions extends AbstractExtension
*/ */
protected $moneyFormatter; protected $moneyFormatter;
/**
* @var RequestStack
*/
protected $requestStack;
/**
* @var array
*/
protected $cookies = [];
/** /**
* @var string[] * @var string[]
*/ */
@@ -88,7 +74,7 @@ class Extensions extends AbstractExtension
'start-small' => 'fas fa-play-circle', 'start-small' => 'fas fa-play-circle',
'stop' => 'fas fa-stop', 'stop' => 'fas fa-stop',
'stop-small' => 'far fa-stop-circle', 'stop-small' => 'far fa-stop-circle',
'timesheet' => 'far fa-clock', 'timesheet' => 'fas fa-clock',
'trash' => 'far fa-trash-alt', 'trash' => 'far fa-trash-alt',
'user' => 'fas fa-user', 'user' => 'fas fa-user',
'visibility' => 'far fa-eye', 'visibility' => 'far fa-eye',
@@ -110,12 +96,10 @@ class Extensions extends AbstractExtension
]; ];
/** /**
* @param RequestStack $requestStack
* @param LocaleSettings $localeSettings * @param LocaleSettings $localeSettings
*/ */
public function __construct(RequestStack $requestStack, LocaleSettings $localeSettings) public function __construct(LocaleSettings $localeSettings)
{ {
$this->requestStack = $requestStack;
$this->localeSettings = $localeSettings; $this->localeSettings = $localeSettings;
$this->durationFormatter = new Duration(); $this->durationFormatter = new Duration();
} }
@@ -142,8 +126,6 @@ class Extensions extends AbstractExtension
{ {
return [ return [
new TwigFunction('locales', [$this, 'getLocales']), new TwigFunction('locales', [$this, 'getLocales']),
new TwigFunction('is_visible_column', [$this, 'isColumnVisible']),
new TwigFunction('is_datatable_configured', [$this, 'isDatatableConfigured']),
new TwigFunction('class_name', [$this, 'getClassName']), new TwigFunction('class_name', [$this, 'getClassName']),
]; ];
} }
@@ -161,61 +143,6 @@ class Extensions extends AbstractExtension
return get_class($object); return get_class($object);
} }
/**
* @param string $dataTable
* @param string $size
* @return bool
*/
public function isDatatableConfigured(string $dataTable, string $size)
{
$cookie = $this->getVisibilityCookieName($dataTable, $size);
return $this->requestStack->getCurrentRequest()->cookies->has($cookie);
}
/**
* @param string $dataTable
* @param string $size
* @return string
*/
public function getVisibilityCookieName(string $dataTable, string $size)
{
return $dataTable . '_visibility' . $size;
}
/**
* This is only for datatables, do not use it outside this context.
*
* @param string $dataTable
* @param string $column
* @param string $size
* @return bool
*/
public function isColumnVisible(string $dataTable, string $column, string $size)
{
// name handling is spread between here and datatables.html.twig (data_table_column_modal)
$cookie = $this->getVisibilityCookieName($dataTable, $size);
if (!isset($this->cookies[$cookie])) {
$visibility = false;
if ($this->requestStack->getCurrentRequest()->cookies->has($cookie)) {
$visibility = json_decode($this->requestStack->getCurrentRequest()->cookies->get($cookie), true);
}
$this->cookies[$cookie] = $visibility;
}
$values = $this->cookies[$cookie];
if (empty($values) || !is_array($values)) {
return true;
}
if (isset($values[$column]) && $values[$column] === false) {
return false;
}
return true;
}
/** /**
* Transforms seconds into a duration string. * Transforms seconds into a duration string.
* *

View File

@@ -0,0 +1,57 @@
<?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\Twig;
use App\Constants;
use App\Entity\Timesheet;
use App\Utils\Duration;
use App\Utils\LocaleSettings;
use NumberFormatter;
use Symfony\Component\Intl\Intl;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class TitleExtension extends AbstractExtension
{
/**
* @var TranslatorInterface
*/
protected $translator;
/**
* @param TranslatorInterface $translator
*/
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return [
new TwigFunction('get_title', [$this, 'generateTitle']),
];
}
/**
* @param null|string $prefix
* @param string $delimiter
* @return string
*/
public function generateTitle(?string $prefix = null, string $delimiter = ' ')
{
return ($prefix ?? '') . 'Kimai' . $delimiter . $this->translator->trans('time_tracking', [], 'messages');
}
}

View File

@@ -32,7 +32,7 @@
{% endblock %} {% endblock %}
{% block title %} {% block title %}
{{ 'browser.title'|trans }} {{- get_title() -}}
{% endblock %} {% endblock %}
{% block page_subtitle %}{% endblock %} {% block page_subtitle %}{% endblock %}

View File

@@ -1,7 +1,7 @@
{% extends '@AdminLTE/FOSUserBundle/Registration/confirmed.html.twig' %} {% extends '@AdminLTE/FOSUserBundle/Registration/confirmed.html.twig' %}
{% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %}
{% block title %}{{ 'browser.title'|trans }}{% endblock %} {% block title %}{{- get_title() -}}{% endblock %}
{% block head %} {% block head %}
{{ parent() }} {{ parent() }}

View File

@@ -1,7 +1,7 @@
{% extends '@AdminLTE/FOSUserBundle/Registration/register.html.twig' %} {% extends '@AdminLTE/FOSUserBundle/Registration/register.html.twig' %}
{% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %}
{% block title %}{{ 'browser.title'|trans }}{% endblock %} {% block title %}{{- get_title() -}}{% endblock %}
{% block head %} {% block head %}
{{ parent() }} {{ parent() }}

View File

@@ -1,7 +1,7 @@
{% extends '@AdminLTE/FOSUserBundle/Resetting/request.html.twig' %} {% extends '@AdminLTE/FOSUserBundle/Resetting/request.html.twig' %}
{% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %}
{% block title %}{{ 'browser.title'|trans }}{% endblock %} {% block title %}{{- get_title() -}}{% endblock %}
{% block head %} {% block head %}
{{ parent() }} {{ parent() }}

View File

@@ -1,7 +1,7 @@
{% extends '@AdminLTE/FOSUserBundle/Security/login.html.twig' %} {% extends '@AdminLTE/FOSUserBundle/Security/login.html.twig' %}
{% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %}
{% block title %}{{ 'browser.title'|trans }}{% endblock %} {% block title %}{{- get_title() -}}{% endblock %}
{% block login_box_icon %} {% block login_box_icon %}
<span class="glyphicon glyphicon-user"></span> <span class="glyphicon glyphicon-user"></span>

View File

@@ -1,7 +1,7 @@
{% extends '@AdminLTE/FOSUserBundle/layout.html.twig' %} {% extends '@AdminLTE/FOSUserBundle/layout.html.twig' %}
{% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %}
{% block title %}{{ 'browser.title'|trans }}{% endblock %} {% block title %}{{- get_title() -}}{% endblock %}
{% block head %} {% block head %}
{{ parent() }} {{ parent() }}

View File

@@ -12,7 +12,7 @@
{% for title, class in entries %} {% for title, class in entries %}
{% if 'alwaysVisible' not in class %} {% if 'alwaysVisible' not in class %}
<div class="form-group"> <div class="form-group">
<input type="checkbox" id="column_{{ title }}" name="{{ title }}"{% if is_visible_column(name, title, '') %} checked="checked"{% endif %}> <input type="checkbox" id="column_{{ title }}" name="{{ title }}"{% if is_visible_column(name, title) %} checked="checked"{% endif %}>
<label class="control-label required" for="column_{{ title }}">{{ ('label.' ~ title)|trans }}</label> <label class="control-label required" for="column_{{ title }}">{{ ('label.' ~ title)|trans }}</label>
</div> </div>
{% endif %} {% endif %}
@@ -45,9 +45,9 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% else %} {% else %}
{% if not is_visible_column(name, column, '') %} {% if not is_visible_column(name, column) %}
{% set classes = classes ~ ' hidden' %} {% set classes = classes ~ ' hidden' %}
{% elseif not is_datatable_configured(name, '') %} {% elseif not is_datatable_configured(name) %}
{% for tmp in classes|split(' ') %} {% for tmp in classes|split(' ') %}
{% if 'hidden' == tmp %} {% if 'hidden' == tmp %}
{% set classes = classes|replace({(tmp): ''}) %} {% set classes = classes|replace({(tmp): ''}) %}

View File

@@ -1 +1 @@
<b>Kimai</b><br>TimeTracking {{- get_title('<b>', '</b><br>')|raw -}}

View File

@@ -36,7 +36,7 @@ class SecurityControllerTest extends ControllerBaseTest
$this->assertTrue($client->getResponse()->isSuccessful()); $this->assertTrue($client->getResponse()->isSuccessful());
$content = $response->getContent(); $content = $response->getContent();
$this->assertContains('<title>Kimai - Time Tracking</title>', $content); $this->assertContains('<title>Kimai Time Tracking</title>', $content);
$this->assertContains('<form action="/en/login_check" method="post">', $content); $this->assertContains('<form action="/en/login_check" method="post">', $content);
$this->assertContains('<input type="text" name="_username"', $content); $this->assertContains('<input type="text" name="_username"', $content);
$this->assertContains('<input name="_password" type="password"', $content); $this->assertContains('<input name="_password" type="password"', $content);
@@ -56,7 +56,7 @@ class SecurityControllerTest extends ControllerBaseTest
$this->assertTrue($response->isSuccessful()); $this->assertTrue($response->isSuccessful());
$content = $response->getContent(); $content = $response->getContent();
$this->assertContains('<title>Kimai - Time Tracking</title>', $content); $this->assertContains('<title>Kimai Time Tracking</title>', $content);
$this->assertContains('Register a new account', $content); $this->assertContains('Register a new account', $content);
$this->assertContains('<form name="fos_user_registration_form" method="post" action="/en/register/" class="fos_user_registration_register">', $content); $this->assertContains('<form name="fos_user_registration_form" method="post" action="/en/register/" class="fos_user_registration_register">', $content);
$this->assertContains('<input type="email"', $content); $this->assertContains('<input type="email"', $content);
@@ -96,7 +96,7 @@ class SecurityControllerTest extends ControllerBaseTest
$this->assertTrue($client->getResponse()->isSuccessful()); $this->assertTrue($client->getResponse()->isSuccessful());
$content = $client->getResponse()->getContent(); $content = $client->getResponse()->getContent();
$this->assertContains('<title>Kimai - Time Tracking</title>', $content); $this->assertContains('<title>Kimai Time Tracking</title>', $content);
$this->assertContains('<p>Congrats example, your account is now activated.</p>', $content); $this->assertContains('<p>Congrats example, your account is now activated.</p>', $content);
$this->assertContains('<a href="/en/homepage">', $content); $this->assertContains('<a href="/en/homepage">', $content);
} }

View File

@@ -50,7 +50,7 @@ abstract class AbstractRendererTest extends KernelTestCase
$translator = $this->getMockBuilder(TranslatorInterface::class)->getMock(); $translator = $this->getMockBuilder(TranslatorInterface::class)->getMock();
$dateExtension = new DateExtensions($localeSettings); $dateExtension = new DateExtensions($localeSettings);
$extensions = new Extensions($requestStack, $localeSettings); $extensions = new Extensions($localeSettings);
return new $classname($translator, $dateExtension, $extensions); return new $classname($translator, $dateExtension, $extensions);
} }

View File

@@ -74,7 +74,7 @@ abstract class AbstractRendererTest extends KernelTestCase
$translator = $this->getMockBuilder(TranslatorInterface::class)->getMock(); $translator = $this->getMockBuilder(TranslatorInterface::class)->getMock();
$dateExtension = new DateExtensions($localeSettings); $dateExtension = new DateExtensions($localeSettings);
$extensions = new Extensions($requestStack, $localeSettings); $extensions = new Extensions($localeSettings);
return new $classname($translator, $dateExtension, $extensions); return new $classname($translator, $dateExtension, $extensions);
} }

View File

@@ -23,7 +23,7 @@ use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
*/ */
class UserDateTimeFactoryTest extends TestCase class UserDateTimeFactoryTest extends TestCase
{ {
public const TEST_TIMEZONE = 'Antarctica/DumontDUrville'; public const TEST_TIMEZONE = 'Europe/London';
protected function createDateTimeFactory(string $timezone) protected function createDateTimeFactory(string $timezone)
{ {

View File

@@ -0,0 +1,46 @@
<?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\Twig;
use App\Twig\DatatableExtensions;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Twig\TwigFunction;
/**
* @covers \App\Twig\DatatableExtensions
*/
class DatatableExtensionsTest extends TestCase
{
protected function getSut(string $locale): DatatableExtensions
{
$request = new Request();
$request->setLocale($locale);
$requestStack = new RequestStack();
$requestStack->push($request);
return new DatatableExtensions($requestStack);
}
public function testGetFunctions()
{
$functions = ['is_visible_column', 'is_datatable_configured'];
$sut = $this->getSut('de');
$twigFunctions = $sut->getFunctions();
$this->assertCount(count($functions), $twigFunctions);
$i = 0;
/** @var TwigFunction $function */
foreach ($twigFunctions as $function) {
$this->assertInstanceOf(TwigFunction::class, $function);
$this->assertEquals($functions[$i++], $function->getName());
}
}
}

View File

@@ -45,7 +45,7 @@ class ExtensionsTest extends TestCase
$localeSettings = new LocaleSettings($requestStack, new LanguageFormattings($locales)); $localeSettings = new LocaleSettings($requestStack, new LanguageFormattings($locales));
return new Extensions($requestStack, $localeSettings); return new Extensions($localeSettings);
} }
public function testGetFilters() public function testGetFilters()
@@ -55,6 +55,7 @@ class ExtensionsTest extends TestCase
$twigFilters = $sut->getFilters(); $twigFilters = $sut->getFilters();
$this->assertCount(count($filters), $twigFilters); $this->assertCount(count($filters), $twigFilters);
$i = 0; $i = 0;
/** @var TwigFilter $filter */
foreach ($twigFilters as $filter) { foreach ($twigFilters as $filter) {
$this->assertInstanceOf(TwigFilter::class, $filter); $this->assertInstanceOf(TwigFilter::class, $filter);
$this->assertEquals($filters[$i++], $filter->getName()); $this->assertEquals($filters[$i++], $filter->getName());
@@ -63,11 +64,12 @@ class ExtensionsTest extends TestCase
public function testGetFunctions() public function testGetFunctions()
{ {
$functions = ['locales', 'is_visible_column', 'is_datatable_configured', 'class_name']; $functions = ['locales', 'class_name'];
$sut = $this->getSut($this->localeDe); $sut = $this->getSut($this->localeDe);
$twigFunctions = $sut->getFunctions(); $twigFunctions = $sut->getFunctions();
$this->assertCount(count($functions), $twigFunctions); $this->assertCount(count($functions), $twigFunctions);
$i = 0; $i = 0;
/** @var TwigFunction $filter */
foreach ($twigFunctions as $filter) { foreach ($twigFunctions as $filter) {
$this->assertInstanceOf(TwigFunction::class, $filter); $this->assertInstanceOf(TwigFunction::class, $filter);
$this->assertEquals($functions[$i++], $filter->getName()); $this->assertEquals($functions[$i++], $filter->getName());

View File

@@ -0,0 +1,52 @@
<?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\Twig;
use App\Twig\TitleExtension;
use PHPUnit\Framework\TestCase;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\TwigFunction;
/**
* @covers \App\Twig\TitleExtension
*/
class TitleExtensionTest extends TestCase
{
protected function getSut(): TitleExtension
{
$translator = $this->getMockBuilder(TranslatorInterface::class)->getMock();
$translator->method('trans')->willReturn('foo');
return new TitleExtension($translator);
}
public function testGetFunctions()
{
$functions = ['get_title'];
$sut = $this->getSut();
$twigFunctions = $sut->getFunctions();
$this->assertCount(count($functions), $twigFunctions);
$i = 0;
/** @var TwigFunction $function */
foreach ($twigFunctions as $function) {
$this->assertInstanceOf(TwigFunction::class, $function);
$this->assertEquals($functions[$i++], $function->getName());
}
}
public function testGetTitle()
{
$sut = $this->getSut();
$this->assertEquals('Kimai foo', $sut->generateTitle());
$this->assertEquals('sdfsdf | Kimai foo', $sut->generateTitle('sdfsdf | '));
$this->assertEquals('<b>Kimai</b> ... foo', $sut->generateTitle('<b>', '</b> ... '));
$this->assertEquals('Kimai | foo', $sut->generateTitle(null, ' | '));
}
}

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Time Tracking</target> <target>Time Tracking</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Zeiterfassung</target> <target>Zeiterfassung</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Time Tracking</target> <target>Time Tracking</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Control de Tiempo</target> <target>Control de Tiempo</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Suivi des temps</target> <target>Suivi des temps</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Időrögzítő</target> <target>Időrögzítő</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Time Tracking</target> <target>Time Tracking</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Time Tracking</target> <target>Time Tracking</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target>Kimai - Учет времени</target> <target>Учет времени</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>

View File

@@ -5,9 +5,9 @@
<!-- <!--
Global template keys Global template keys
--> -->
<trans-unit id="browser.title"> <trans-unit id="time_tracking">
<source>browser.title</source> <source>time_tracking</source>
<target state="translated">Kimai - Tidsredovisning</target> <target state="translated">Tidsredovisning</target>
</trans-unit> </trans-unit>
<trans-unit id="yes"> <trans-unit id="yes">
<source>yes</source> <source>yes</source>