diff --git a/src/API/TimesheetController.php b/src/API/TimesheetController.php index 008248080..5729dd7d0 100644 --- a/src/API/TimesheetController.php +++ b/src/API/TimesheetController.php @@ -21,6 +21,7 @@ use App\Repository\Query\TimesheetQuery; use App\Repository\TagRepository; use App\Repository\TimesheetRepository; +use App\Repository\UserRepository; use App\Timesheet\TimesheetService; use App\Timesheet\TrackingMode\TrackingModeInterface; use App\Utils\SearchTerm; @@ -75,19 +76,22 @@ class TimesheetController extends BaseApiController * @var TimesheetService */ private $service; + private $userRepository; public function __construct( ViewHandlerInterface $viewHandler, TimesheetRepository $repository, TagRepository $tagRepository, EventDispatcherInterface $dispatcher, - TimesheetService $service + TimesheetService $service, + UserRepository $userRepository ) { $this->viewHandler = $viewHandler; $this->repository = $repository; $this->tagRepository = $tagRepository; $this->dispatcher = $dispatcher; $this->service = $service; + $this->userRepository = $userRepository; } protected function getTrackingMode(): TrackingModeInterface @@ -491,9 +495,13 @@ public function recentAction(ParamFetcherInterface $paramFetcher): Response if ($this->isGranted('view_other_timesheet') && null !== ($reqUser = $paramFetcher->get('user'))) { if ('all' === $reqUser) { - $reqUser = null; + $user = null; + } else { + $user = $this->userRepository->getUserById($reqUser); + if ($user === null) { + throw $this->createNotFoundException('Unknown User ID'); + } } - $user = $reqUser; } if (null !== ($reqLimit = $paramFetcher->get('size'))) { diff --git a/src/Constants.php b/src/Constants.php index 4c24ad062..0bc774fe2 100644 --- a/src/Constants.php +++ b/src/Constants.php @@ -17,11 +17,11 @@ class Constants /** * The current release version */ - public const VERSION = '1.30.3'; + public const VERSION = '1.30.4'; /** * The current release: major * 10000 + minor * 100 + patch */ - public const VERSION_ID = 13003; + public const VERSION_ID = 13004; /** * The current release status, either "stable" or "dev" */ diff --git a/src/Controller/InvoiceController.php b/src/Controller/InvoiceController.php index a8b8ad2a5..bed0cccbb 100644 --- a/src/Controller/InvoiceController.php +++ b/src/Controller/InvoiceController.php @@ -44,6 +44,7 @@ use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Twig\Environment; /** * Controller used to create invoices and manage invoice templates. @@ -409,7 +410,7 @@ public function editTemplateAction(InvoiceTemplate $template, Request $request): * @Route(path="/document_upload", name="admin_invoice_document_upload", methods={"GET", "POST"}) * @Security("is_granted('upload_invoice_template')") */ - public function uploadDocumentAction(Request $request, string $projectDirectory, InvoiceDocumentRepository $documentRepository) + public function uploadDocumentAction(Request $request, string $projectDirectory, InvoiceDocumentRepository $documentRepository, Environment $twig, SystemConfiguration $systemConfiguration) { $dir = $documentRepository->getUploadDirectory(); $invoiceDir = $dir; @@ -418,6 +419,7 @@ public function uploadDocumentAction(Request $request, string $projectDirectory, if ($invoiceDir[0] !== '/') { $invoiceDir = $projectDirectory . DIRECTORY_SEPARATOR . $dir; } + $invoiceDir = rtrim($invoiceDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; $used = []; foreach ($this->templateRepository->findAll() as $template) { @@ -473,23 +475,56 @@ public function uploadDocumentAction(Request $request, string $projectDirectory, /** @var UploadedFile $uploadedFile */ $uploadedFile = $form->get('document')->getData(); - $originalFilename = pathinfo($uploadedFile->getClientOriginalName(), PATHINFO_FILENAME); - $safeFilename = transliterator_transliterate( - 'Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()', - $originalFilename - ); + $originalName = $uploadedFile->getClientOriginalName(); + $safeFilename = null; + $extension = null; + $success = true; - $extension = $uploadedFile->guessExtension(); + $allowed = InvoiceDocumentUploadForm::EXTENSIONS_NO_TWIG; + if ((bool) $systemConfiguration->find('invoice.upload_twig') === true) { + $allowed = InvoiceDocumentUploadForm::EXTENSIONS; + } - $newFilename = substr($safeFilename, 0, 20) . '.' . $extension; + foreach ($allowed as $ext) { + $len = \strlen($ext); + if (substr_compare($originalName, $ext, -$len) === 0) { + $extension = $ext; + $withoutExtension = str_replace($ext, '', $originalName); + $safeFilename = transliterator_transliterate(InvoiceDocumentUploadForm::FILENAME_RULE, $withoutExtension); + break; + } + } - try { - $uploadedFile->move($invoiceDir, $newFilename); + if ($safeFilename === null || $extension === null) { + $success = false; + $this->flashError('Invalid file given'); + } else { + $newFilename = substr($safeFilename, 0, 20) . $extension; + + try { + $uploadedFile->move($invoiceDir, $newFilename); + + // if this is a twig file, we directly try to compile the template + if (stripos($newFilename, '.twig') !== false) { + try { + $twig->enableAutoReload(); + $twig->load('@invoice/' . $newFilename); + $twig->disableAutoReload(); + } catch (Exception $ex) { + unlink($invoiceDir . $newFilename); + $success = false; + $this->flashException($ex, 'File was deleted, as Twig template is broken: ' . $ex->getMessage()); + } + } + } catch (Exception $ex) { + $this->flashException($ex, 'action.upload.error'); + } + } + + if ($success) { $this->flashSuccess('action.update.success'); return $this->redirectToRoute('admin_invoice_document_upload'); - } catch (Exception $ex) { - $this->flashException($ex, 'action.upload.error'); } } } diff --git a/src/Controller/SystemConfigurationController.php b/src/Controller/SystemConfigurationController.php index f55e1af17..0f69f55cb 100644 --- a/src/Controller/SystemConfigurationController.php +++ b/src/Controller/SystemConfigurationController.php @@ -495,6 +495,7 @@ protected function getConfigurationTypes() ->setLabel('invoice.number_format') ->setRequired(true) ->setType(TextType::class) + ->setConstraints([new NotBlank()]) ->setTranslationDomain('system-configuration'), (new Configuration()) ->setName('invoice.simple_form') diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index e2f3b0856..4f8467146 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -333,6 +333,9 @@ private function getInvoiceNode(): ArrayNodeDefinition ->scalarNode('number_format') ->defaultValue('{Y}/{cy,3}') ->end() + ->booleanNode('upload_twig') + ->defaultTrue() + ->end() ->end() ; diff --git a/src/Form/InvoiceDocumentUploadForm.php b/src/Form/InvoiceDocumentUploadForm.php index 661111825..0b28c8e64 100644 --- a/src/Form/InvoiceDocumentUploadForm.php +++ b/src/Form/InvoiceDocumentUploadForm.php @@ -9,6 +9,7 @@ namespace App\Form; +use App\Configuration\SystemConfiguration; use App\Repository\InvoiceDocumentRepository; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\FileType; @@ -21,11 +22,18 @@ class InvoiceDocumentUploadForm extends AbstractType { + public const EXTENSIONS = ['.html.twig', '.pdf.twig', '.docx', '.xlsx', '.ods']; + public const EXTENSIONS_NO_TWIG = ['.docx', '.xlsx', '.ods']; + public const FILENAME_RULE = 'Any-Latin; Latin-ASCII; [^A-Za-z0-9_\-] remove; Lower()'; + private $repository; + private $systemConfiguration; + private $extensions = []; - public function __construct(InvoiceDocumentRepository $repository) + public function __construct(InvoiceDocumentRepository $repository, SystemConfiguration $systemConfiguration) { $this->repository = $repository; + $this->systemConfiguration = $systemConfiguration; } /** @@ -33,22 +41,32 @@ public function __construct(InvoiceDocumentRepository $repository) */ public function buildForm(FormBuilderInterface $builder, array $options) { + $this->extensions = self::EXTENSIONS_NO_TWIG; + $extensions = 'DOCX, ODS, XLSX'; $mimetypes = [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.oasis.opendocument.spreadsheet', ]; + if ((bool) $this->systemConfiguration->find('invoice.upload_twig') === true) { + $this->extensions = self::EXTENSIONS; + $extensions = 'DOCX, ODS, XLSX, TWIG (PDF & HTML)'; + $mimetypes = array_merge($mimetypes, [ + 'application/octet-stream', // needed for twig templates + 'text/html', // needed for twig templates + 'text/plain', // needed for twig templates + ]); + } + $builder ->add('document', FileType::class, [ 'label' => 'label.invoice_renderer', 'translation_domain' => 'invoice-renderer', 'help' => 'help.upload', + 'help_translation_parameters' => ['%extensions%' => $extensions], 'mapped' => false, 'required' => true, - 'attr' => [ - 'accept' => implode(',', $mimetypes) - ], 'constraints' => [ new File([ 'mimeTypes' => $mimetypes, @@ -77,6 +95,48 @@ public function validateDocument($value, ExecutionContextInterface $context) ->setTranslationDomain('validators') ->setCode('kimai-invoice-document-upload-01') ->addViolation(); + + return; + } + + $extension = null; + $nameWithoutExtension = null; + + foreach ($this->extensions as $ext) { + $len = \strlen($ext); + if (substr_compare($name, $ext, -$len) === 0) { + $extension = $ext; + $nameWithoutExtension = str_replace($ext, '', $name); + break; + } + } + + if ($extension === null) { + $context->buildViolation('This invoice document cannot be used, allowed file extensions are: %extensions%') + ->setParameters(['%extensions%' => implode(', ', $this->extensions)]) + ->setTranslationDomain('validators') + ->setCode('kimai-invoice-document-upload-02') + ->addViolation(); + + return; + } + + $safeFilename = transliterator_transliterate(self::FILENAME_RULE, $nameWithoutExtension); + + if ($safeFilename !== $nameWithoutExtension) { + $context->buildViolation('This invoice document cannot be used, filename may only contain the following ascii character: %character%') + ->setParameters(['%character%' => 'A-Z a-z 0-9 _ -']) + ->setTranslationDomain('validators') + ->setCode('kimai-invoice-document-upload-03') + ->addViolation(); + } + + if (mb_strlen($nameWithoutExtension) > 20) { + $context->buildViolation('This invoice document cannot be used, allowed filename length without extension is %character% character.') + ->setParameters(['%character%' => 20]) + ->setTranslationDomain('validators') + ->setCode('kimai-invoice-document-upload-04') + ->addViolation(); } } diff --git a/src/Invoice/Renderer/PdfRenderer.php b/src/Invoice/Renderer/PdfRenderer.php index fd58bc6ae..d431d8d6c 100644 --- a/src/Invoice/Renderer/PdfRenderer.php +++ b/src/Invoice/Renderer/PdfRenderer.php @@ -15,6 +15,7 @@ use App\Export\ExportContext; use App\Invoice\InvoiceFilename; use App\Invoice\InvoiceModel; +use App\Utils\FileHelper; use App\Utils\HtmlToPdfConverter; use Symfony\Component\HttpFoundation\Response; use Twig\Environment; @@ -61,6 +62,8 @@ public function render(InvoiceDocument $document, InvoiceModel $model): Response $response = new Response($content); + $filename = FileHelper::convertToAsciiFilename($filename); + $disposition = $response->headers->makeDisposition($this->getDisposition(), $filename . '.pdf'); $response->headers->set('Content-Type', 'application/pdf'); diff --git a/tests/API/TimesheetControllerTest.php b/tests/API/TimesheetControllerTest.php index 3c0177294..74928880a 100644 --- a/tests/API/TimesheetControllerTest.php +++ b/tests/API/TimesheetControllerTest.php @@ -773,6 +773,36 @@ public function testGetRecentAction() self::assertApiResponseTypeStructure('TimesheetCollectionFull', $result[0]); } + public function testGetRecentActionForUser(): void + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); + + $start = new \DateTime('-10 days'); + + $user = $this->getUserByRole(User::ROLE_ADMIN); + $fixture = new TimesheetFixtures(); + $fixture->setFixedRate(true); + $fixture->setHourlyRate(true); + $fixture->setAmount(10); + $fixture->setUser($user); + $fixture->setStartDate($start); + $this->importFixture($fixture); + + $query = [ + 'user' => $user->getId(), + 'size' => 2, + 'begin' => $start->format(self::DATE_FORMAT_HTML5), + ]; + + $this->assertAccessIsGranted($client, '/api/timesheets/recent', 'GET', $query); + $result = json_decode($client->getResponse()->getContent(), true); + + $this->assertIsArray($result); + $this->assertNotEmpty($result); + $this->assertEquals(1, \count($result)); + self::assertApiResponseTypeStructure('TimesheetCollectionFull', $result[0]); + } + public function testActiveAction() { $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); diff --git a/tests/DependencyInjection/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php index 60c48c2fd..08ac9798a 100644 --- a/tests/DependencyInjection/ConfigurationTest.php +++ b/tests/DependencyInjection/ConfigurationTest.php @@ -325,6 +325,7 @@ public function testFullDefaultConfig() ], 'simple_form' => false, 'number_format' => '{Y}/{cy,3}', + 'upload_twig' => true, ], 'export' => [ 'documents' => [ diff --git a/translations/invoice-renderer.ar.xlf b/translations/invoice-renderer.ar.xlf index 9b3f5dc45..a8f4dbb3f 100644 --- a/translations/invoice-renderer.ar.xlf +++ b/translations/invoice-renderer.ar.xlf @@ -60,7 +60,7 @@ help.upload - انتباه: سيتم الكتابة فوق الملفات الموجودة. أنواع الملفات المسموح بها هي: DOCX و ODS و XLSX. + انتباه: سيتم الكتابة فوق الملفات الموجودة. أنواع الملفات المسموح بها هي: %extensions%. programmatic diff --git a/translations/invoice-renderer.cs.xlf b/translations/invoice-renderer.cs.xlf index 31e031c72..3439b2bbf 100644 --- a/translations/invoice-renderer.cs.xlf +++ b/translations/invoice-renderer.cs.xlf @@ -36,7 +36,7 @@ help.upload - Pozor: existující soubory budou přepsány. Povolené typy jsou: DOCX, ODS, XLSX. + Pozor: existující soubory budou přepsány. Povolené typy jsou: %extensions%. programmatic diff --git a/translations/invoice-renderer.de.xlf b/translations/invoice-renderer.de.xlf index e00901d5a..a4b0f163d 100644 --- a/translations/invoice-renderer.de.xlf +++ b/translations/invoice-renderer.de.xlf @@ -8,7 +8,7 @@ help.upload - Achtung: existierende Dateien werden überschrieben. Erlaubte Dateitypen sind: DOCX, ODS, XLSX. + Achtung: existierende Dateien werden überschrieben. Erlaubte Dateitypen sind: %extensions%. diff --git a/translations/invoice-renderer.de_CH.xlf b/translations/invoice-renderer.de_CH.xlf index 482dee7ae..892981739 100644 --- a/translations/invoice-renderer.de_CH.xlf +++ b/translations/invoice-renderer.de_CH.xlf @@ -8,7 +8,7 @@ help.upload - Achtung: existierende Dateien werden überschrieben. Erlaubte Dateitypen sind: DOCX, ODS, XLSX + Achtung: existierende Dateien werden überschrieben. Erlaubte Dateitypen sind: %extensions% diff --git a/translations/invoice-renderer.el.xlf b/translations/invoice-renderer.el.xlf index b06085218..a54a9ea37 100644 --- a/translations/invoice-renderer.el.xlf +++ b/translations/invoice-renderer.el.xlf @@ -8,7 +8,7 @@ help.upload - Προσοχή: τα υπάρχοντα αρχεία θα αντικατασταθούν. Επιτρεπόμενοι τύποι αρχείων είναι: DOCX, ODS, XLSX. + Προσοχή: τα υπάρχοντα αρχεία θα αντικατασταθούν. Επιτρεπόμενοι τύποι αρχείων είναι: %extensions%. diff --git a/translations/invoice-renderer.en.xlf b/translations/invoice-renderer.en.xlf index ada2e1bee..5924cc869 100644 --- a/translations/invoice-renderer.en.xlf +++ b/translations/invoice-renderer.en.xlf @@ -8,7 +8,7 @@ help.upload - Attention: existing files will be overwritten. Allowed file types are: DOCX, ODS, XLSX. + Attention: existing files will be overwritten. Allowed file types are: %extensions%. diff --git a/translations/invoice-renderer.eo.xlf b/translations/invoice-renderer.eo.xlf index d593f57be..77790e6de 100644 --- a/translations/invoice-renderer.eo.xlf +++ b/translations/invoice-renderer.eo.xlf @@ -36,7 +36,7 @@ help.upload - Atentu: ekzistantaj dosieroj estos anstataŭigitaj. Permesitaj tipoj de dosieroj estas: DOCX, ODS, XLSX. + Atentu: ekzistantaj dosieroj estos anstataŭigitaj. Permesitaj tipoj de dosieroj estas: %extensions%. diff --git a/translations/invoice-renderer.es.xlf b/translations/invoice-renderer.es.xlf index a24f65a74..c26efa6e3 100644 --- a/translations/invoice-renderer.es.xlf +++ b/translations/invoice-renderer.es.xlf @@ -44,7 +44,7 @@ help.upload - Atención: Los archivos existentes serán sobrescritos. Los tipos de archivo permitidos son: DOCX, ODS, XLSX. + Atención: Los archivos existentes serán sobrescritos. Los tipos de archivo permitidos son: %extensions%. programmatic diff --git a/translations/invoice-renderer.fa.xlf b/translations/invoice-renderer.fa.xlf index 6eec2df5c..e17f128f2 100644 --- a/translations/invoice-renderer.fa.xlf +++ b/translations/invoice-renderer.fa.xlf @@ -8,7 +8,7 @@ help.upload - توجه: فایل های موجود رونویسی خواهند شد. فایل های مجاز عبارتند از: DOCX، ODS، XLSX. + توجه: فایل های موجود رونویسی خواهند شد. فایل های مجاز عبارتند از: %extensions%. diff --git a/translations/invoice-renderer.fi.xlf b/translations/invoice-renderer.fi.xlf index 0c34721e5..35373b2af 100644 --- a/translations/invoice-renderer.fi.xlf +++ b/translations/invoice-renderer.fi.xlf @@ -8,7 +8,7 @@ help.upload - Huomioitavaa: olemassa olevat tiedostot korvataan. Sallitut tiedosto tyypit on: DOCX, ODS, XLSX. + Huomioitavaa: olemassa olevat tiedostot korvataan. Sallitut tiedosto tyypit on: %extensions%. diff --git a/translations/invoice-renderer.fo.xlf b/translations/invoice-renderer.fo.xlf index 250d89248..788695643 100644 --- a/translations/invoice-renderer.fo.xlf +++ b/translations/invoice-renderer.fo.xlf @@ -8,7 +8,7 @@ help.upload - Attention: existing files will be overwritten. Allowed file types are: DOCX, ODS, XLSX. + Attention: existing files will be overwritten. Allowed file types are: %extensions%. diff --git a/translations/invoice-renderer.fr.xlf b/translations/invoice-renderer.fr.xlf index 0f9c1558a..9c319f67d 100644 --- a/translations/invoice-renderer.fr.xlf +++ b/translations/invoice-renderer.fr.xlf @@ -48,7 +48,7 @@ help.upload - Attention : les fichiers existants seront écrasés. Les types de fichiers autorisés sont : DOCX, ODS, XLSX. + Attention : les fichiers existants seront écrasés. Les types de fichiers autorisés sont : %extensions%. programmatic diff --git a/translations/invoice-renderer.he.xlf b/translations/invoice-renderer.he.xlf index fc5da027b..7166ee373 100644 --- a/translations/invoice-renderer.he.xlf +++ b/translations/invoice-renderer.he.xlf @@ -36,7 +36,7 @@ help.upload - שים לב: קבצים קיימים ידרסו וימחקו. סוגי קבצים מותרים: DOCX, ODS, XLSX. + שים לב: קבצים קיימים ידרסו וימחקו. סוגי קבצים מותרים: %extensions%. Microsoft Excel (XLSX) diff --git a/translations/invoice-renderer.hr.xlf b/translations/invoice-renderer.hr.xlf index 36b230925..ac4ca3d8c 100644 --- a/translations/invoice-renderer.hr.xlf +++ b/translations/invoice-renderer.hr.xlf @@ -8,7 +8,7 @@ help.upload - Oprez: postojeće datoteke će se prepisati. Dopuštene vrste datoteka su: DOCX, ODS, XLSX. + Oprez: postojeće datoteke će se prepisati. Dopuštene vrste datoteka su: %extensions%. diff --git a/translations/invoice-renderer.hu.xlf b/translations/invoice-renderer.hu.xlf index 37b45319b..0d5ee3d7e 100644 --- a/translations/invoice-renderer.hu.xlf +++ b/translations/invoice-renderer.hu.xlf @@ -40,7 +40,7 @@ help.upload - Figyelem: a meglévő fájlok felülíródnak. A megengedett fájltípusok: DOCX, ODS, XLSX. + Figyelem: a meglévő fájlok felülíródnak. A megengedett fájltípusok: %extensions%. programmatic diff --git a/translations/invoice-renderer.ko.xlf b/translations/invoice-renderer.ko.xlf index a67a93da2..3d31eec56 100644 --- a/translations/invoice-renderer.ko.xlf +++ b/translations/invoice-renderer.ko.xlf @@ -44,7 +44,7 @@ help.upload - 주의: 기존 파일을 덮어씁니다. 허용되는 파일 형식은 DOCX, ODS, XLSX입니다. + 주의: 기존 파일을 덮어씁니다. 허용되는 파일 형식은 %extensions%입니다. Html diff --git a/translations/invoice-renderer.nb_NO.xlf b/translations/invoice-renderer.nb_NO.xlf index 979f6f5f9..aaa4abb81 100644 --- a/translations/invoice-renderer.nb_NO.xlf +++ b/translations/invoice-renderer.nb_NO.xlf @@ -8,7 +8,7 @@ help.upload - Obs: Eksisterende filer vil bli overskrevet. Filtypene DOCX, ODS og XLSX støttes. + Obs: Eksisterende filer vil bli overskrevet. Filtypene %extensions% støttes. diff --git a/translations/invoice-renderer.nl.xlf b/translations/invoice-renderer.nl.xlf index 770ab4397..987d1c909 100644 --- a/translations/invoice-renderer.nl.xlf +++ b/translations/invoice-renderer.nl.xlf @@ -8,7 +8,7 @@ help.upload - Attentie: Bestaande bestanden zullen overschreven worden. Toegestaande bestandstypes zijn: DOCX, ODS, XLSX. + Attentie: Bestaande bestanden zullen overschreven worden. Toegestaande bestandstypes zijn: %extensions%. diff --git a/translations/invoice-renderer.pl.xlf b/translations/invoice-renderer.pl.xlf index c456304f2..19b61a8cf 100644 --- a/translations/invoice-renderer.pl.xlf +++ b/translations/invoice-renderer.pl.xlf @@ -44,7 +44,7 @@ help.upload - Uwaga: istniejące pliki zostaną nadpisane. Dozwolone typu plików to: DOCX, ODS, XLSX. + Uwaga: istniejące pliki zostaną nadpisane. Dozwolone typu plików to: %extensions%. programmatic diff --git a/translations/invoice-renderer.pt.xlf b/translations/invoice-renderer.pt.xlf index 40d6f3921..2e96e7bb9 100644 --- a/translations/invoice-renderer.pt.xlf +++ b/translations/invoice-renderer.pt.xlf @@ -8,7 +8,7 @@ help.upload - Atenção: os ficheiros já existentes serão substituídos. Os tipos de ficheiros permitidos são: DOCX, ODS, XLSX. + Atenção: os ficheiros já existentes serão substituídos. Os tipos de ficheiros permitidos são: %extensions%. diff --git a/translations/invoice-renderer.pt_BR.xlf b/translations/invoice-renderer.pt_BR.xlf index d7ec9a1e8..236420411 100644 --- a/translations/invoice-renderer.pt_BR.xlf +++ b/translations/invoice-renderer.pt_BR.xlf @@ -36,7 +36,7 @@ help.upload - Atenção: os arquivos já existentes serão substituídos. Os tipos dos arquivos permitidos são: DOCX, ODS, XLSX. + Atenção: os arquivos já existentes serão substituídos. Os tipos dos arquivos permitidos são: %extensions%. Html diff --git a/translations/invoice-renderer.ro.xlf b/translations/invoice-renderer.ro.xlf index 86b386435..9f9f661e9 100644 --- a/translations/invoice-renderer.ro.xlf +++ b/translations/invoice-renderer.ro.xlf @@ -36,7 +36,7 @@ help.upload - Atenție: fișierele existente vor fi suprascrise. Tipuri de fișiere permise: DOCX, ODS, XLSX. + Atenție: fișierele existente vor fi suprascrise. Tipuri de fișiere permise: %extensions%. programmatic diff --git a/translations/invoice-renderer.ru.xlf b/translations/invoice-renderer.ru.xlf index c6431dfe6..5d8b19713 100644 --- a/translations/invoice-renderer.ru.xlf +++ b/translations/invoice-renderer.ru.xlf @@ -20,7 +20,7 @@ help.upload - Внимание: существующие файлы будут перезаписаны. Допустимые типы файлов: DOCX, ODS, XLSX. + Внимание: существующие файлы будут перезаписаны. Допустимые типы файлов: %extensions%. programmatic diff --git a/translations/invoice-renderer.sv.xlf b/translations/invoice-renderer.sv.xlf index 37927eb99..22fe0adfd 100644 --- a/translations/invoice-renderer.sv.xlf +++ b/translations/invoice-renderer.sv.xlf @@ -8,7 +8,7 @@ help.upload - Obs: redan exsiterande filer kommer att skrivas över. Tillåtna fil typer är: DOCX, ODS, XLSX. + Obs: redan exsiterande filer kommer att skrivas över. Tillåtna fil typer är: %extensions%. default diff --git a/translations/invoice-renderer.tr.xlf b/translations/invoice-renderer.tr.xlf index 652024e1b..4537fd7ce 100644 --- a/translations/invoice-renderer.tr.xlf +++ b/translations/invoice-renderer.tr.xlf @@ -60,7 +60,7 @@ help.upload - Dikkat: mevcut dosyaların üzerine yazılacaktır. İzin verilen dosya türleri: DOCX, ODS, XLSX. + Dikkat: mevcut dosyaların üzerine yazılacaktır. İzin verilen dosya türleri: %extensions%. Html diff --git a/translations/invoice-renderer.uk.xlf b/translations/invoice-renderer.uk.xlf index 0077e8352..9ec98606d 100644 --- a/translations/invoice-renderer.uk.xlf +++ b/translations/invoice-renderer.uk.xlf @@ -8,7 +8,7 @@ help.upload - Увага: існуючі файли будуть перезаписані. Дозволені типи файлів: DOCX, ODS, XLSX. + Увага: існуючі файли будуть перезаписані. Дозволені типи файлів: %extensions%. diff --git a/translations/invoice-renderer.vi.xlf b/translations/invoice-renderer.vi.xlf index e635c02db..2feb91ded 100644 --- a/translations/invoice-renderer.vi.xlf +++ b/translations/invoice-renderer.vi.xlf @@ -36,7 +36,7 @@ help.upload - Chú ý: các tệp hiện có sẽ bị ghi đè. Các loại tệp được phép là: DOCX, ODS, XLSX. + Chú ý: các tệp hiện có sẽ bị ghi đè. Các loại tệp được phép là: %extensions%. programmatic diff --git a/translations/invoice-renderer.zh_CN.xlf b/translations/invoice-renderer.zh_CN.xlf index 443e829ab..67c716364 100644 --- a/translations/invoice-renderer.zh_CN.xlf +++ b/translations/invoice-renderer.zh_CN.xlf @@ -60,7 +60,7 @@ help.upload - 注意:现有文件将被覆盖。允许的文件类型是:DOCX, ODS, XLSX. + 注意:现有文件将被覆盖。允许的文件类型是:%extensions%. programmatic