Compare commits
3 Commits
2.0.0-beta
...
2.0.0-rc-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f32448b9f5 | ||
|
|
f3b4078c6a | ||
|
|
ca846b5fbf |
@@ -1,11 +1,10 @@
|
||||
framework:
|
||||
cache:
|
||||
# Unique name of your app: used to compute stable namespaces for cache keys.
|
||||
prefix_seed: "kimai"
|
||||
|
||||
# Redis
|
||||
#app: cache.adapter.redis
|
||||
#default_redis_provider: redis://localhost
|
||||
#default_redis_provider: redis://127.0.0.1:6379
|
||||
|
||||
#app: cache.adapter.memcached
|
||||
#default_memcached_provider: 'memcached://localhost'
|
||||
|
||||
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
|
||||
#app: cache.adapter.apcu
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
security:
|
||||
enable_authenticator_manager: true
|
||||
|
||||
password_hashers:
|
||||
App\Entity\User: auto
|
||||
|
||||
|
||||
@@ -7,12 +7,7 @@ services:
|
||||
public: true
|
||||
|
||||
App\Configuration\SystemConfiguration:
|
||||
arguments: ['@App\Repository\ConfigurationRepository', "%kimai.config%"]
|
||||
|
||||
App\Repository\ConfigurationRepository:
|
||||
class: Doctrine\ORM\EntityRepository
|
||||
factory: ['@doctrine.orm.entity_manager', getRepository]
|
||||
arguments: ['App\Entity\Configuration']
|
||||
arguments: ['@App\Configuration\ConfigurationService', "%kimai.config%"]
|
||||
|
||||
# required for the importer command test
|
||||
App\Repository\UserRepository:
|
||||
|
||||
30
phpstan.neon
30
phpstan.neon
@@ -915,36 +915,16 @@ parameters:
|
||||
count: 1
|
||||
path: src/Configuration/SystemConfiguration.php
|
||||
|
||||
-
|
||||
message: "#^Offset \\(int\\|string\\) might not exist on array\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Configuration/SystemConfiguration.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$array of function array_filter expects array, array\\|null given\\.$#"
|
||||
count: 2
|
||||
path: src/Configuration/SystemConfiguration.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$key of method App\\\\Configuration\\\\SystemConfiguration\\:\\:set\\(\\) expects string, mixed given\\.$#"
|
||||
count: 1
|
||||
path: src/Configuration/SystemConfiguration.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$key of method App\\\\Configuration\\\\SystemConfiguration\\:\\:set\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Configuration/SystemConfiguration.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$string of function trim expects string, bool\\|float\\|int\\|string given\\.$#"
|
||||
count: 1
|
||||
path: src/Configuration/SystemConfiguration.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$array of function array_key_exists expects array, array\\|null given\\.$#"
|
||||
count: 3
|
||||
path: src/Configuration/SystemConfiguration.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\AbstractController\\:\\:createFormForGetRequest\\(\\) has parameter \\$data with no type specified\\.$#"
|
||||
count: 1
|
||||
@@ -1615,11 +1595,6 @@ parameters:
|
||||
count: 3
|
||||
path: src/Controller/SystemConfigurationController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$model of method App\\\\Repository\\\\ConfigurationRepository\\:\\:saveSystemConfiguration\\(\\) expects App\\\\Form\\\\Model\\\\SystemConfiguration, mixed given\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/SystemConfigurationController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$value of method App\\\\Form\\\\Model\\\\Configuration\\:\\:setValue\\(\\) expects bool\\|int\\|object\\|string\\|null, bool\\|float\\|int\\|string given\\.$#"
|
||||
count: 1
|
||||
@@ -6360,11 +6335,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Repository/BookmarkRepository.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Repository\\\\ConfigurationRepository\\:\\:saveSystemConfiguration\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Repository/ConfigurationRepository.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getSearchFields\\(\\) on App\\\\Utils\\\\SearchTerm\\|null\\.$#"
|
||||
count: 1
|
||||
|
||||
@@ -9,18 +9,13 @@
|
||||
|
||||
namespace App\Configuration;
|
||||
|
||||
use App\Entity\Configuration;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
interface ConfigLoaderInterface
|
||||
{
|
||||
/**
|
||||
* @param string $name
|
||||
* @return ?Configuration
|
||||
*/
|
||||
public function getConfiguration(string $name): ?Configuration;
|
||||
|
||||
/**
|
||||
* @return Configuration[]
|
||||
* @return array<string, string|null>
|
||||
*/
|
||||
public function getConfigurations(): array;
|
||||
}
|
||||
|
||||
72
src/Configuration/ConfigurationService.php
Normal file
72
src/Configuration/ConfigurationService.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?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\Configuration;
|
||||
|
||||
use App\Entity\Configuration;
|
||||
use App\Form\Model\SystemConfiguration;
|
||||
use App\Repository\ConfigurationRepository;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
use Symfony\Contracts\Cache\ItemInterface;
|
||||
|
||||
final class ConfigurationService implements ConfigLoaderInterface
|
||||
{
|
||||
/**
|
||||
* @var array<string, string|null>
|
||||
*/
|
||||
private static array $cacheAll = [];
|
||||
private static bool $initialized = false;
|
||||
|
||||
public function __construct(private ConfigurationRepository $configurationRepository, private CacheInterface $cache)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string|null>
|
||||
*/
|
||||
public function getConfigurations(): array
|
||||
{
|
||||
if (self::$initialized === true) {
|
||||
return self::$cacheAll;
|
||||
}
|
||||
|
||||
self::$cacheAll = $this->cache->get('configurations', function (ItemInterface $item) {
|
||||
$item->expiresAfter(86400); // one day
|
||||
|
||||
return $this->configurationRepository->getConfigurations();
|
||||
});
|
||||
|
||||
self::$initialized = true;
|
||||
|
||||
return self::$cacheAll;
|
||||
}
|
||||
|
||||
public function getConfiguration(string $name): ?Configuration
|
||||
{
|
||||
return $this->configurationRepository->findOneBy(['name' => $name]);
|
||||
}
|
||||
|
||||
public function clearCache(): void
|
||||
{
|
||||
$this->cache->delete('configurations');
|
||||
self::$initialized = false;
|
||||
}
|
||||
|
||||
public function saveConfiguration(Configuration $configuration): void
|
||||
{
|
||||
$this->configurationRepository->saveConfiguration($configuration);
|
||||
$this->clearCache();
|
||||
}
|
||||
|
||||
public function saveSystemConfiguration(SystemConfiguration $model): void
|
||||
{
|
||||
$this->configurationRepository->saveSystemConfiguration($model);
|
||||
$this->clearCache();
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ final class SystemConfiguration
|
||||
{
|
||||
private bool $initialized = false;
|
||||
|
||||
public function __construct(private ConfigLoaderInterface $repository, private ?array $settings)
|
||||
public function __construct(private ConfigLoaderInterface $repository, private array $settings = [])
|
||||
{
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ final class SystemConfiguration
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->repository->getConfigurations() as $configuration) {
|
||||
$this->set($configuration->getName(), $configuration->getValue());
|
||||
foreach ($this->repository->getConfigurations() as $key => $value) {
|
||||
$this->set($key, $value);
|
||||
}
|
||||
|
||||
$this->initialized = true;
|
||||
@@ -35,7 +35,6 @@ final class SystemConfiguration
|
||||
*
|
||||
* If no key is given to the method, the entire array will be replaced.
|
||||
*
|
||||
* @see https://github.com/divineomega/array_undot
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
@@ -70,6 +69,7 @@ final class SystemConfiguration
|
||||
/**
|
||||
* This method should be avoided if possible, use plain keys instead.
|
||||
*
|
||||
* @see https://github.com/divineomega/array_undot
|
||||
* @param string $key
|
||||
* @return array
|
||||
*/
|
||||
@@ -219,7 +219,7 @@ final class SystemConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
* @return array<int, array<'saml'|'kimai', string>>
|
||||
*/
|
||||
public function getSamlRolesMapping(): array
|
||||
{
|
||||
@@ -227,7 +227,7 @@ final class SystemConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
* @return array<string, array<mixed>|bool>
|
||||
*/
|
||||
public function getSamlConnection(): array
|
||||
{
|
||||
@@ -235,7 +235,7 @@ final class SystemConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<mixed>
|
||||
* @return array<int, array<'saml'|'kimai', string>>
|
||||
*/
|
||||
public function getSamlAttributeMapping(): array
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Configuration\ConfigurationService;
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Event\SystemConfigurationEvent;
|
||||
use App\Form\Model\Configuration;
|
||||
@@ -30,7 +31,6 @@ use App\Form\Type\TimezoneType;
|
||||
use App\Form\Type\TrackingModeType;
|
||||
use App\Form\Type\WeekDaysType;
|
||||
use App\Form\Type\YesNoType;
|
||||
use App\Repository\ConfigurationRepository;
|
||||
use App\Timesheet\LockdownService;
|
||||
use App\Utils\PageSetup;
|
||||
use App\Validator\Constraints\ColorChoices;
|
||||
@@ -61,7 +61,7 @@ use Symfony\Component\Validator\Constraints\Regex;
|
||||
#[IsGranted('system_configuration')]
|
||||
final class SystemConfigurationController extends AbstractController
|
||||
{
|
||||
public function __construct(private EventDispatcherInterface $eventDispatcher, private ConfigurationRepository $repository, private SystemConfiguration $systemConfiguration, private LockdownService $lockdownService)
|
||||
public function __construct(private EventDispatcherInterface $eventDispatcher, private ConfigurationService $repository, private SystemConfiguration $systemConfiguration, private LockdownService $lockdownService)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -142,7 +142,9 @@ final class SystemConfigurationController extends AbstractController
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
try {
|
||||
$this->repository->saveSystemConfiguration($form->getData());
|
||||
/** @var SystemConfigurationModel $saveModel */
|
||||
$saveModel = $form->getData();
|
||||
$this->repository->saveSystemConfiguration($saveModel);
|
||||
$this->flashSuccess('action.update.success');
|
||||
} catch (\Exception $ex) {
|
||||
$this->handleFormUpdateException($ex, $form);
|
||||
|
||||
@@ -21,7 +21,7 @@ final class MailType extends AbstractType
|
||||
$resolver->setDefaults([
|
||||
'label' => 'email',
|
||||
'constraints' => [
|
||||
new Email(['mode' => 'loose'])
|
||||
new Email(['mode' => 'html5'])
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Configuration\ConfigLoaderInterface;
|
||||
use App\Entity\Configuration;
|
||||
use App\Form\Model\SystemConfiguration;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
@@ -17,74 +16,36 @@ use Doctrine\ORM\Exception\ORMException;
|
||||
|
||||
/**
|
||||
* @extends EntityRepository<Configuration>
|
||||
* @internal use App\Configuration\ConfigurationService instead
|
||||
* @final
|
||||
*/
|
||||
class ConfigurationRepository extends EntityRepository implements ConfigLoaderInterface
|
||||
class ConfigurationRepository extends EntityRepository
|
||||
{
|
||||
private const CACHE_KEY = 'ConfigurationRepository_All';
|
||||
/**
|
||||
* @var array<string, Configuration>
|
||||
*/
|
||||
private static array $cacheAll = [];
|
||||
private static bool $initialized = false;
|
||||
|
||||
public function clearCache(): void
|
||||
{
|
||||
self::$cacheAll = [];
|
||||
self::$initialized = false;
|
||||
|
||||
$cache = $this->getEntityManager()->getConfiguration()->getResultCache();
|
||||
if ($cache !== null && $cache->hasItem(self::CACHE_KEY)) {
|
||||
$cache->deleteItem(self::CACHE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
private function prefillCache(): void
|
||||
{
|
||||
if (self::$initialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->createQueryBuilder('s')->getQuery();
|
||||
$query->enableResultCache(86400, self::CACHE_KEY);
|
||||
|
||||
$configs = $query->getResult();
|
||||
foreach ($configs as $config) {
|
||||
self::$cacheAll[$config->getName()] = $config;
|
||||
}
|
||||
self::$initialized = true;
|
||||
}
|
||||
|
||||
public function saveConfiguration(Configuration $configuration): void
|
||||
{
|
||||
$entityManager = $this->getEntityManager();
|
||||
$entityManager->persist($configuration);
|
||||
$entityManager->flush();
|
||||
$this->clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Configuration[]
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function getConfigurations(): array
|
||||
{
|
||||
$this->prefillCache();
|
||||
$query = $this->createQueryBuilder('s')->select('s.name')->addSelect('s.value')->getQuery();
|
||||
/** @var array<int, array<'name'|'value', string>> $result */
|
||||
$result = $query->getArrayResult();
|
||||
|
||||
return array_values(self::$cacheAll);
|
||||
}
|
||||
|
||||
public function getConfiguration(string $name): ?Configuration
|
||||
{
|
||||
$this->prefillCache();
|
||||
|
||||
if (!\array_key_exists($name, self::$cacheAll)) {
|
||||
return null;
|
||||
$all = [];
|
||||
foreach ($result as $row) {
|
||||
$all[$row['name']] = $row['value'];
|
||||
}
|
||||
|
||||
return self::$cacheAll[$name];
|
||||
return $all;
|
||||
}
|
||||
|
||||
public function saveSystemConfiguration(SystemConfiguration $model)
|
||||
public function saveSystemConfiguration(SystemConfiguration $model): void
|
||||
{
|
||||
$em = $this->getEntityManager();
|
||||
$em->beginTransaction();
|
||||
@@ -120,7 +81,5 @@ class ConfigurationRepository extends EntityRepository implements ConfigLoaderIn
|
||||
$em->rollback();
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
$this->clearCache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,29 +18,22 @@ use App\Entity\Configuration;
|
||||
class TestConfigLoader implements ConfigLoaderInterface
|
||||
{
|
||||
/**
|
||||
* @var Configuration[]
|
||||
* @var array<string, string|null>
|
||||
*/
|
||||
private array $configs;
|
||||
private array $configs = [];
|
||||
|
||||
/**
|
||||
* @param Configuration[] $configs
|
||||
*/
|
||||
public function __construct(array $configs)
|
||||
{
|
||||
$this->configs = $configs;
|
||||
}
|
||||
|
||||
public function getConfiguration(string $name): ?Configuration
|
||||
{
|
||||
if (!\array_key_exists($name, $this->configs)) {
|
||||
return null;
|
||||
foreach ($configs as $config) {
|
||||
$this->configs[$config->getName()] = $config->getValue();
|
||||
}
|
||||
|
||||
return $this->configs[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Configuration[]
|
||||
* @return array<string, string|null>
|
||||
*/
|
||||
public function getConfigurations(): array
|
||||
{
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Configuration\ConfigurationService;
|
||||
use App\DataFixtures\UserFixtures;
|
||||
use App\Entity\Configuration;
|
||||
use App\Entity\User;
|
||||
use App\Form\Type\DateRangeType;
|
||||
use App\Repository\ConfigurationRepository;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Tests\KernelTestTrait;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
@@ -89,9 +89,10 @@ abstract class ControllerBaseTest extends WebTestCase
|
||||
|
||||
protected function setSystemConfiguration(string $name, $value): void
|
||||
{
|
||||
$repository = self::getContainer()->get(ConfigurationRepository::class);
|
||||
/** @var ConfigurationService $repository */
|
||||
$repository = self::getContainer()->get(ConfigurationService::class);
|
||||
|
||||
$entity = $repository->findOneBy(['name' => $name]);
|
||||
$entity = $repository->getConfiguration($name);
|
||||
if ($entity === null) {
|
||||
$entity = new Configuration();
|
||||
$entity->setName($name);
|
||||
@@ -103,9 +104,9 @@ abstract class ControllerBaseTest extends WebTestCase
|
||||
|
||||
protected function clearConfigCache()
|
||||
{
|
||||
/** @var ConfigurationRepository $repository */
|
||||
$repository = self::getContainer()->get(ConfigurationRepository::class);
|
||||
$repository->clearCache();
|
||||
/** @var ConfigurationService $service */
|
||||
$service = self::getContainer()->get(ConfigurationService::class);
|
||||
$service->clearCache();
|
||||
}
|
||||
|
||||
protected function getClientForAuthenticatedUser(string $role = User::ROLE_USER): HttpKernelBrowser
|
||||
|
||||
@@ -10,11 +10,9 @@
|
||||
namespace App\Tests\Controller;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Entity\Configuration;
|
||||
use App\Entity\Timesheet;
|
||||
use App\Entity\TimesheetMeta;
|
||||
use App\Entity\User;
|
||||
use App\Repository\ConfigurationRepository;
|
||||
use App\Repository\TagRepository;
|
||||
use App\Tests\DataFixtures\ActivityFixtures;
|
||||
use App\Tests\DataFixtures\TagFixtures;
|
||||
@@ -442,12 +440,7 @@ class TimesheetControllerTest extends ControllerBaseTest
|
||||
$response = $client->getResponse();
|
||||
$this->assertTrue($response->isSuccessful());
|
||||
|
||||
/** @var ConfigurationRepository $repository */
|
||||
$repository = $this->getEntityManager()->getRepository(Configuration::class);
|
||||
$config = new Configuration();
|
||||
$config->setName('timesheet.rules.allow_overbooking_budget');
|
||||
$config->setValue(false);
|
||||
$repository->saveConfiguration($config);
|
||||
$this->setSystemConfiguration('timesheet.rules.allow_overbooking_budget', false);
|
||||
|
||||
$this->assertHasValidationError(
|
||||
$client,
|
||||
@@ -496,12 +489,7 @@ class TimesheetControllerTest extends ControllerBaseTest
|
||||
$response = $client->getResponse();
|
||||
$this->assertTrue($response->isSuccessful());
|
||||
|
||||
/** @var ConfigurationRepository $repository */
|
||||
$repository = $this->getEntityManager()->getRepository(Configuration::class);
|
||||
$config = new Configuration();
|
||||
$config->setName('timesheet.rules.allow_zero_duration');
|
||||
$config->setValue(false);
|
||||
$repository->saveConfiguration($config);
|
||||
$this->setSystemConfiguration('timesheet.rules.allow_zero_duration', false);
|
||||
|
||||
$this->assertHasValidationError(
|
||||
$client,
|
||||
|
||||
@@ -2867,11 +2867,6 @@ parameters:
|
||||
count: 4
|
||||
path: Controller/CalendarControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method findOneBy\\(\\) on object\\|null\\.$#"
|
||||
count: 1
|
||||
path: Controller/ControllerBaseTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getRepository\\(\\) on object\\|null\\.$#"
|
||||
count: 1
|
||||
@@ -2887,11 +2882,6 @@ parameters:
|
||||
count: 1
|
||||
path: Controller/ControllerBaseTest.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method saveConfiguration\\(\\) on object\\|null\\.$#"
|
||||
count: 1
|
||||
path: Controller/ControllerBaseTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Controller\\\\ControllerBaseTest\\:\\:assert404\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en" target-language="de" datatype="plaintext" original="about.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="oYYDCG5" resname="support">
|
||||
<source>support</source>
|
||||
<target>Forum</target>
|
||||
<source>Support</source>
|
||||
<target state="needs-translation">Support</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="dHqPOYO" approved="yes" resname="website">
|
||||
<source>website</source>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en" target-language="en" datatype="plaintext" original="about.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="oYYDCG5" resname="support">
|
||||
<source>support</source>
|
||||
<target>Forum</target>
|
||||
<source>Support</source>
|
||||
<target state="translated">Support</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="dHqPOYO" resname="website">
|
||||
<source>website</source>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="BPiZbad" resname="user">
|
||||
<source>user</source>
|
||||
<target>تم تجميع المستخدم - إدخال واحد لكل مستخدم</target>
|
||||
<target state="translated">مجموعة مستخدمين: إدخال واحد لكل مستخدم</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="aDtTH0H" resname="price">
|
||||
<source>price</source>
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
<source>programmatic</source>
|
||||
<target state="translated">لمزيد من المعالجة</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="22pt8Gs" resname="download_invoice_renderer">
|
||||
<source>download_invoice_renderer</source>
|
||||
<target state="translated">يمكنك تنزيل المزيد من النماذج هنا</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
<source>text</source>
|
||||
<target>Text</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="22pt8Gs" resname="download_invoice_renderer">
|
||||
<source>download_invoice_renderer</source>
|
||||
<target state="translated">Puteți descărca alte modele aici</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
@@ -286,7 +286,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="MQKiG33" resname="profile.preferences">
|
||||
<source>profile.preferences</source>
|
||||
<target>تفضيلات</target>
|
||||
<target state="translated">التفضيلات</target>
|
||||
</trans-unit>
|
||||
<!--
|
||||
Admin: Timesheet
|
||||
@@ -698,7 +698,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="hBNESu6" resname="my.profile">
|
||||
<source>my.profile</source>
|
||||
<target>ملف التعريف الخاص بي</target>
|
||||
<target state="translated">ملفي التعريفي</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="JBkykGe" resname="search">
|
||||
<source>search</source>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-->
|
||||
<trans-unit id="N7mikjJ" resname="time_tracking">
|
||||
<source>time_tracking</source>
|
||||
<target>رهگیری زمان</target>
|
||||
<target state="translated">ردیابی زمان</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="inmIkP6" resname="yes">
|
||||
<source>yes</source>
|
||||
@@ -35,7 +35,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="vDd3alC" resname="admin_entity.delete_confirm">
|
||||
<source>admin_entity.delete_confirm</source>
|
||||
<target>این داده به خوبی پاک خواهد شد! متناوبا، از سوی دیگر شما میتوانید یک ورودی را انتخاب نمایید که تمام داده ها به آن ترجمه شوند:</target>
|
||||
<target state="translated">این داده ها نیز حذف خواهند شد! از طرف دیگر، می توانید یک ورودی را انتخاب کنید که تمام داده ها به آن منتقل شوند:</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="COyxNde" resname="delete.not_in_use">
|
||||
<source>delete.not_in_use</source>
|
||||
@@ -75,11 +75,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="0M_Gylq" resname="rates.empty">
|
||||
<source>rates.empty</source>
|
||||
<target>فایلی هنوز تنظیم نشده است.</target>
|
||||
<target state="translated">هیچ قیمتی تنظیم نشده است</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="mflwMcX" resname="rates.title">
|
||||
<source>rates.title</source>
|
||||
<target>هزینه ها</target>
|
||||
<target state="translated">قیمت ها</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="zFfl7jw" resname="sum.total">
|
||||
<source>sum.total</source>
|
||||
@@ -110,11 +110,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="aq59Sk8" resname="api_token_repeat">
|
||||
<source>api_token_repeat</source>
|
||||
<target>ریست پسورد API</target>
|
||||
<target state="translated">تکرار پسورد API</target>
|
||||
</trans-unit>
|
||||
<trans-unit id=".372.o7" resname="login_required">
|
||||
<source>login_required</source>
|
||||
<target>مجوز را گم کرده. به صفحه ورود انتقال دهد؟</target>
|
||||
<target state="translated">مجوز از دست رفته است. تغییر مسیر برای ورود به سیستم؟</target>
|
||||
</trans-unit>
|
||||
<!--
|
||||
Menu / Navbar items
|
||||
@@ -349,7 +349,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="yxQop43" resname="all_times">
|
||||
<source>all_times</source>
|
||||
<target>برنامه های زمانی</target>
|
||||
<target state="translated">همیشه</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ypVQO7o" resname="menu.reporting">
|
||||
<source>menu.reporting</source>
|
||||
@@ -404,8 +404,8 @@
|
||||
<target>رنگ</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="GzWKgBk" resname="error.directory_missing">
|
||||
<source>error.directory_missing</source>
|
||||
<target>موقعیت "%dir%" وجود ندارد و قابل ساختن نیست.</target>
|
||||
<source>The directory “%dir%” does not exist and could not be created.</source>
|
||||
<target state="translated">دایرکتوری "%dir%" وجود ندارد و نمی تواند ایجاد شود.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="C2TGff0" resname="error.directory_protected">
|
||||
<source>error.directory_protected</source>
|
||||
@@ -484,8 +484,8 @@
|
||||
<target>حذف جستجوی علاقه مندی</target>
|
||||
</trans-unit>
|
||||
<trans-unit id=".ndupSK" resname="registration.check_email">
|
||||
<source>registration.check_email</source>
|
||||
<target>ایمیلی برای %email% شامل لینک فعالسازی ارسال شد. جهت فعال کردن حساب کاربری خود باید بر روی آن کلیک کنید.</target>
|
||||
<source>An e-mail has been sent to %email%. It contains a link you must click to activate your account.</source>
|
||||
<target state="translated">ایمیلی شامل لینک فعالسازی به %email% ارسال شد. جهت فعال کردن حساب کاربری خود باید بر روی آن کلیک کنید.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="_cY.wHP" resname="resetting.check_email">
|
||||
<source>resetting.check_email</source>
|
||||
@@ -1365,11 +1365,11 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="wYcx0So" resname="search.no_results">
|
||||
<source>search.no_results</source>
|
||||
<target state="needs-translation">No results found for "%input%"</target>
|
||||
<target state="translated">هیچ نتیجه ای برای "%input%" یافت نشد</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="biHjm0h" resname="select.add_new">
|
||||
<source>select.add_new</source>
|
||||
<target state="needs-translation">ایجاد جدید با نام "%input%"</target>
|
||||
<target state="translated">ایجاد نام جدید با "%input%"</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="dru_Thv" resname="please_choose">
|
||||
<source>please_choose</source>
|
||||
|
||||
@@ -980,10 +980,6 @@
|
||||
<source>export</source>
|
||||
<target>Izvoz</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="KxuVIAw" resname="export.subtitle">
|
||||
<source>export.subtitle</source>
|
||||
<target>Izvezi podatke vremenske tablice u razne formate</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="iwWaUoa" resname="export.filter">
|
||||
<source>export.filter</source>
|
||||
<target>Filtriraj podatke za izvoz</target>
|
||||
|
||||
@@ -81,8 +81,8 @@
|
||||
Login / Security
|
||||
-->
|
||||
<trans-unit id="XohImNo" resname="password">
|
||||
<source>password</source>
|
||||
<target state="needs-translation">Password</target>
|
||||
<source>Password</source>
|
||||
<target state="translated">Password</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hLEZkoC" resname="password_repeat">
|
||||
<source>password_repeat</source>
|
||||
|
||||
@@ -1222,6 +1222,178 @@
|
||||
<source>Apps</source>
|
||||
<target state="translated">Aplikacje</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="3rJ5QDP" resname="help.teams">
|
||||
<source>help.teams</source>
|
||||
<target state="translated">Ogranicza widoczność do wybranych zespołów.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="FgKTw5v" resname="login.2fa_label">
|
||||
<source>login.2fa_label</source>
|
||||
<target state="translated">Kod potwierdzający</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="3WHV.yf" resname="activated">
|
||||
<source>Activated</source>
|
||||
<target state="translated">Aktywowane</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IDDfzoR" resname="invoiceLabel">
|
||||
<source>invoiceLabel</source>
|
||||
<target state="translated">Tekst na fakturze</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="On18MKP" resname="plugin.installed">
|
||||
<source>plugin.installed</source>
|
||||
<target state="translated">Zainstalowane wtyczki</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ojfv7Jl" resname="invoice_form.title">
|
||||
<source>invoice_form.title</source>
|
||||
<target state="translated">Utwórz fakturę</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="mQMcndl" resname="stats.userAmountToday">
|
||||
<source>stats.userAmountToday</source>
|
||||
<target state="translated">Mój dzisiejszy przychód</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="LDS9o5X" resname="stats.userAmountWeek">
|
||||
<source>stats.userAmountWeek</source>
|
||||
<target state="translated">Moje przychody w tym tygodniu</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="EedlgkM" resname="stats.userDurationTotal">
|
||||
<source>stats.userDurationTotal</source>
|
||||
<target state="translated">Moje całkowite godziny pracy</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="LDsHBXd" resname="modal.columns.label">
|
||||
<source>modal.columns.label</source>
|
||||
<target state="translated">Kolumny tabeli</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="FeFBn_3" resname="profile.2fa">
|
||||
<source>profile.2fa</source>
|
||||
<target state="translated">Dwuskładnikowe (TOTP)</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="o0hsx2H" resname="mark_as_open">
|
||||
<source>mark_as_open</source>
|
||||
<target state="translated">Oznacz jako otwarte</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="EI5gPkp" resname="stats.userDurationToday">
|
||||
<source>stats.userDurationToday</source>
|
||||
<target state="translated">Moje dzisiejsze godziny pracy</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="9jlbhkf" resname="stats.userAmountTotal">
|
||||
<source>stats.userAmountTotal</source>
|
||||
<target state="translated">Moje całkowite przychody</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="E3Kj9lt" resname="stats.userAmountMonth">
|
||||
<source>stats.userAmountMonth</source>
|
||||
<target state="translated">Moje przychody w tym miesiącu</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="xvdsZsS" resname="stats.userAmountYear">
|
||||
<source>stats.userAmountYear</source>
|
||||
<target state="translated">Moje przychody w tym roku</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="DXcvOMM" resname="stats.userDurationWeek">
|
||||
<source>stats.userDurationWeek</source>
|
||||
<target state="translated">Moje godziny pracy w tym tygodniu</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="0Hhg4zQ" resname="system_account.help">
|
||||
<source>system_account.help</source>
|
||||
<target state="translated">Będzie ukryty w raportach i listach rozwijanych</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="0WpgaGa" resname="stats.userDurationMonth">
|
||||
<source>stats.userDurationMonth</source>
|
||||
<target state="translated">Moje godziny pracy w tym miesiącu</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="BjyLITj" resname="stats.userDurationYear">
|
||||
<source>stats.userDurationYear</source>
|
||||
<target state="translated">Moje godziny pracy w tym roku</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="wYcx0So" resname="search.no_results">
|
||||
<source>search.no_results</source>
|
||||
<target state="translated">Nie znaleziono żadnych wyników dla "%input%"</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="2lL9ACs" resname="help.invoiceTemplate">
|
||||
<source>help.invoiceTemplate</source>
|
||||
<target state="translated">Faktura jest generowana za pomocą tego szablonu.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="5kFod8o" resname="team.configure_teamlead.help">
|
||||
<source>team.configure_teamlead.help</source>
|
||||
<target state="translated">Wybrani / wyróżnieni użytkownicy są liderami zespołu.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="biHjm0h" resname="select.add_new">
|
||||
<source>select.add_new</source>
|
||||
<target state="translated">Utwórz nowy o nazwie "%input%"</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="JSBReoa" resname="api_password.intro">
|
||||
<source>api_password.intro</source>
|
||||
<target state="translated">Hasło interfejsu API jest używane do komunikacji pomiędzy Kimai a Twoimi aplikacjami</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="hPY2VcD" resname="profile.2fa_intro">
|
||||
<source>profile.2fa_intro</source>
|
||||
<target state="translated">Nowe urządzenie można aktywować, skanując obraz w aplikacji.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="wwrREDg" resname="pagination">
|
||||
<source>pagination</source>
|
||||
<target state="translated">Pokaż wpisy %start% do %end% z %total%.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IRzPWmL" resname="login.2fa_intro">
|
||||
<source>login.2fa_intro</source>
|
||||
<target state="translated">Proszę wpisać kod potwierdzający, aby zakończyć proces logowania.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="aGk9Aqt" resname="desktop">
|
||||
<source>desktop</source>
|
||||
<target state="translated">Komputer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Y0PRG9Z" resname="profile.2fa_confirmation">
|
||||
<source>profile.2fa_confirmation</source>
|
||||
<target state="translated">Potwierdź kod, który aktywuje uwierzytelnianie dwuskładnikowe dla tego konta.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="SdLZTel" resname="favorite_routes">
|
||||
<source>favorite_routes</source>
|
||||
<target state="translated">Ulubione</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="i7aSJ1i" resname="notifications">
|
||||
<source>notifications</source>
|
||||
<target state="translated">Powiadomienia</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="0ZWvn12" resname="notifications.welcome">
|
||||
<source>notifications.welcome</source>
|
||||
<target state="translated">Dziękujemy za wyrażenie zgody na powiadomienia!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="PLLl1E0" resname="system_account">
|
||||
<source>system_account</source>
|
||||
<target state="translated">Konto systemowe</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="t.jgy7A" resname="all_invoices">
|
||||
<source>all_invoices</source>
|
||||
<target state="translated">Historia faktur</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="5NugIxO" resname="includeWithBudget">
|
||||
<source>includeWithBudget</source>
|
||||
<target state="translated">Pokaż wpisy z budżetem</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="WOFPb2i" resname="skin.dark">
|
||||
<source>skin.dark</source>
|
||||
<target state="translated">Ciemny</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="mjKOAgQ" resname="skin.light">
|
||||
<source>skin.light</source>
|
||||
<target state="translated">Jasny</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="dru_Thv" resname="please_choose">
|
||||
<source>please_choose</source>
|
||||
<target state="translated">Proszę wybrać</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="WbT2QLP" resname="extended_settings">
|
||||
<source>extended_settings</source>
|
||||
<target state="translated">Ustawienia rozszerzone</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="ZZaqTEr" resname="no_activity">
|
||||
<source>no_activity</source>
|
||||
<target state="translated">Bez aktywności</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="QT8.BCN" resname="api_password.missing_title">
|
||||
<source>api_password.missing_title</source>
|
||||
<target state="translated">Nie można użyć interfejsu API</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Uu8YvYV" resname="deactivated">
|
||||
<source>Deactivated</source>
|
||||
<target state="translated">Dezaktywowane</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="ebTjBb9" resname="my_times">
|
||||
<source>my_times</source>
|
||||
<target>Meus tempos</target>
|
||||
<target state="translated">Meus horários</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="yxQop43" resname="all_times">
|
||||
<source>all_times</source>
|
||||
@@ -271,7 +271,7 @@
|
||||
-->
|
||||
<trans-unit id="VXj0Y3h" resname="timesheet.title">
|
||||
<source>timesheet.title</source>
|
||||
<target>Meus Tempos</target>
|
||||
<target state="translated">Meus horários</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="dwEVXUR" resname="timesheet.edit">
|
||||
<source>timesheet.edit</source>
|
||||
@@ -476,23 +476,23 @@
|
||||
-->
|
||||
<trans-unit id="TdBJBAl" resname="stats.durationToday">
|
||||
<source>stats.durationToday</source>
|
||||
<target>Horas de trabalho hoje</target>
|
||||
<target state="translated">Horas trabalhadas hoje</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="XhKalZH" resname="stats.durationWeek">
|
||||
<source>stats.durationWeek</source>
|
||||
<target>Horas de trabalho esta semana</target>
|
||||
<target state="translated">Horas trabalhadas esta semana</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="uaOwf_P" resname="stats.durationMonth">
|
||||
<source>stats.durationMonth</source>
|
||||
<target>Horas de trabalho este mês</target>
|
||||
<target state="translated">Horas trabalhadas este mês</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="WqF84KR" resname="stats.durationYear">
|
||||
<source>stats.durationYear</source>
|
||||
<target>Horas de trabalho este ano</target>
|
||||
<target state="translated">Horas trabalhadas este ano</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="YtvPnl1" resname="stats.durationTotal">
|
||||
<source>stats.durationTotal</source>
|
||||
<target>Total de horas de trabalho</target>
|
||||
<target state="translated">Total de horas trabalhadas</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IFOLMgp" resname="stats.yourWorkingHours">
|
||||
<source>stats.yourWorkingHours</source>
|
||||
@@ -1060,7 +1060,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="xkugSAA" resname="stats.durationFinancialYear">
|
||||
<source>stats.durationFinancialYear</source>
|
||||
<target>Horário de trabalho neste ano fiscal</target>
|
||||
<target state="translated">Horários de trabalho neste ano fiscal</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="HWB4OGJ" resname="stats.workingTimeFinancialYear">
|
||||
<source>stats.workingTimeFinancialYear</source>
|
||||
@@ -1396,7 +1396,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="wwrREDg" resname="pagination">
|
||||
<source>pagination</source>
|
||||
<target state="translated">Mostrar as entradas %start% a %end% do %total%.</target>
|
||||
<target state="translated">Mostrar as entradas de %start% até %end% de %total%.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="mjKOAgQ" resname="skin.light">
|
||||
<source>skin.light</source>
|
||||
|
||||
@@ -1202,6 +1202,46 @@
|
||||
<source>about.title</source>
|
||||
<target>Om Kimai</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1MfS6X5" resname="remove_filter">
|
||||
<source>remove_filter</source>
|
||||
<target state="translated">Nollställ sökfilter</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="fQ3Prt4" resname="security.unlock.title">
|
||||
<source>security.unlock.title</source>
|
||||
<target state="translated">Lås upp konto</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="nqEYrfk" resname="security.unlock.intro">
|
||||
<source>security.unlock.intro</source>
|
||||
<target state="translated">Vänligen ange ditt lösenord för fullständig åtkomst</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="853W5Iu" resname="security.unlock.button">
|
||||
<source>security.unlock.button</source>
|
||||
<target state="translated">Lås upp</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Eq2E_Rd" resname="menu.apps">
|
||||
<source>Apps</source>
|
||||
<target state="translated">Applikationer</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="3rJ5QDP" resname="help.teams">
|
||||
<source>help.teams</source>
|
||||
<target state="translated">Begränsar synligheten till de valda lagen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="aOJITgv" resname="help.invoiceText">
|
||||
<source>help.invoiceText</source>
|
||||
<target state="translated">Denna text används i fakturadokument och kan användas t.ex. att notera ytterligare leveransvillkor.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="IDDfzoR" resname="invoiceLabel">
|
||||
<source>invoiceLabel</source>
|
||||
<target state="translated">Fakturatext</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="jLzX0Ae" resname="help.invoiceLabel">
|
||||
<source>help.invoiceLabel</source>
|
||||
<target state="translated">Den här texten ersätter objektets namn, vilket tillåter mer detaljerade etiketter för fakturaartiklar.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="AeMGtJO" resname="help.visible">
|
||||
<source>help.visible</source>
|
||||
<target state="translated">Om inställningen är avstängd visas inte objektet i rullgardinsrutor och listvyer.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
6
translations/plugins.ro.xlf
Executable file → Normal file
6
translations/plugins.ro.xlf
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en" target-language="ro" datatype="plaintext" original="plugins.en.xlf">
|
||||
<body>
|
||||
@@ -6,6 +6,10 @@
|
||||
<source>plugin.none_installed</source>
|
||||
<target>Nu există nici un plugin instalat.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="zVtBsSo" resname="plugin.marketplace">
|
||||
<source>plugin.marketplace</source>
|
||||
<target state="translated">Plugin-uri noi de pe piață</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
@@ -282,6 +282,14 @@
|
||||
<source>calendar.title_pattern</source>
|
||||
<target state="translated">عرض عناوين إدخالات التقويم</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="LmOfuE5" resname="customer.number_format">
|
||||
<source>customer.number_format</source>
|
||||
<target state="translated">شكل رقم الزبون</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1cAQPNS" resname="customer.allow_duplicate_number">
|
||||
<source>customer.allow_duplicate_number</source>
|
||||
<target state="translated">السماح بتكرار رقم الحساب</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
@@ -290,6 +290,18 @@
|
||||
<source>activity.allow_inline_create</source>
|
||||
<target state="translated">Zezwalaj na tworzenie działań w formie śledzenia czasu</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="LmOfuE5" resname="customer.number_format">
|
||||
<source>customer.number_format</source>
|
||||
<target state="translated">Format numeru klienta</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="1cAQPNS" resname="customer.allow_duplicate_number">
|
||||
<source>customer.allow_duplicate_number</source>
|
||||
<target state="translated">Zezwalaj na duplikowanie numeru konta</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="pBxkAF_" resname="copy_teams_on_create" approved="no">
|
||||
<source>copy_teams_on_create</source>
|
||||
<target state="translated">Przejmij zespoły od zalogowanego użytkownika podczas tworzenia nowych wpisów</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
||||
35
translations/wizard.ar.xlf
Normal file
35
translations/wizard.ar.xlf
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
|
||||
<file source-language="en" target-language="ar" datatype="plaintext" original="wizard.en.xlf">
|
||||
<body>
|
||||
<trans-unit id="9XidDHG" resname="wizard.intro.title">
|
||||
<source>wizard.intro.title</source>
|
||||
<target state="translated">مرحبا بكم في Kimai</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="X0ws5mu" resname="wizard.intro.description">
|
||||
<source>wizard.intro.description</source>
|
||||
<target state="translated">سيساعدك هذا المساعِد على تخصيص Kimai وفقا لاحتياجاتك.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="FCMK0ph" resname="wizard.separator">
|
||||
<source>wizard.separator</source>
|
||||
<target state="translated">إعداداتك</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="8_e6ApF" resname="wizard.profile.title">
|
||||
<source>wizard.profile.title</source>
|
||||
<target state="translated">ملفك الشخصي</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="Mo1506M" resname="wizard.profile.description">
|
||||
<source>wizard.profile.description</source>
|
||||
<target state="translated">بعض الإعدادات الأساسية لتسهيل عملك مع Kimai.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="8p.2pXa" resname="wizard.done.title">
|
||||
<source>wizard.done.title</source>
|
||||
<target state="translated">تهانينا</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="k1SzMuI" resname="wizard.done.description">
|
||||
<source>wizard.done.description</source>
|
||||
<target state="translated">اكتملت الآن أهم الإعدادات. هناك العديد من الأشياء الأخرى التي يمكنك تخصيصها لاحقا في ملف تعريف المستخدم الخاص بك.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
Reference in New Issue
Block a user