Added translations

This commit is contained in:
Chris Kankiewicz
2020-02-24 14:28:53 -07:00
parent db1dc84e9e
commit 118771e243
28 changed files with 536 additions and 52 deletions

View File

@@ -14,6 +14,15 @@ return [
*/
'debug' => Helpers::env('DEBUG'),
/**
* The application interface language.
*
* Possible values: See 'app/languages' folder for available translations.
*
* Defualt value: en
*/
'language' => Helpers::env('LANGUAGE'),
/**
* Enable dark mode?
*

View File

@@ -18,6 +18,7 @@ class AppManager
protected const PROVIDERS = [
Providers\ConfigProvider::class,
Providers\FinderProvider::class,
Providers\TranslationProvider::class,
Providers\TwigProvider::class,
Providers\WhoopsProvider::class,
];

View File

@@ -7,24 +7,27 @@ use Psr\Http\Message\ServerRequestInterface;
use Slim\Interfaces\ErrorHandlerInterface;
use Slim\Psr7\Response;
use Slim\Views\Twig;
use Symfony\Contracts\Translation\TranslatorInterface;
use Throwable;
class ErrorHandler implements ErrorHandlerInterface
{
/** @const The default error message string */
protected const DEFAULT_ERROR_MESSAGE = 'An unexpected error occured';
/** @var Twig Twig templating component */
protected $view;
/** @var TranslatorInterface Translation component */
protected $translator;
/**
* Create a new ErrorHandler object.
*
* @param \Slim\Views\Twig $view
* @param \Slim\Views\Twig $view
* @param \Symfony\Contracts\Translation\TranslatorInterface $translator
*/
public function __construct(Twig $view)
public function __construct(Twig $view, TranslatorInterface $translator)
{
$this->view = $view;
$this->translator = $translator;
}
/**
@@ -49,15 +52,15 @@ class ErrorHandler implements ErrorHandlerInterface
if (in_array('application/json', explode(',', $request->getHeaderLine('Accept')))) {
$response->getBody()->write(json_encode([
'error' => ['message' => self::DEFAULT_ERROR_MESSAGE]
'error' => ['message' => $this->translator->trans('error.unexpected')]
]));
return $response->withHeader('Content-Type', 'application/json');
}
return $this->view->render($response, 'error.twig', [
'message' => self::DEFAULT_ERROR_MESSAGE,
'subtext' => 'Enable debugging for additional information',
'message' => $this->translator->trans('error.unexpected'),
'subtext' => $this->translator->trans('enable_debugging'),
]);
}
}

View File

@@ -10,6 +10,7 @@ use Slim\Views\Twig;
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Contracts\Translation\TranslatorInterface;
class DirectoryHandler
{
@@ -22,18 +23,27 @@ class DirectoryHandler
/** @var Twig Twig templating component */
protected $view;
/** @var TranslatorInterface Translator component */
protected $translator;
/**
* Create a new IndexController object.
*
* @param \PHLAK\Config\Config $config
* @param \Symfony\Component\Finder\Finder $finder
* @param \Slim\Views\Twig $view
* @param \PHLAK\Config\Config $config
* @param \Symfony\Component\Finder\Finder $finder
* @param \Slim\Views\Twig $view
* @param \Symfony\Contracts\Translation\TranslatorInterface $translator
*/
public function __construct(Config $config, Finder $finder, Twig $view)
{
public function __construct(
Config $config,
Finder $finder,
Twig $view,
TranslatorInterface $translator
) {
$this->config = $config;
$this->finder = $finder;
$this->view = $view;
$this->translator = $translator;
}
/**
@@ -52,7 +62,7 @@ class DirectoryHandler
$files = $this->finder->in($path)->depth(0);
} catch (DirectoryNotFoundException $exception) {
return $this->view->render($response->withStatus(404), 'error.twig', [
'message' => 'Directory does not exist'
'message' => $this->translator->trans('error.directory_not_found')
]);
}

View File

@@ -8,6 +8,7 @@ use Psr\Http\Message\ResponseInterface;
use Slim\Psr7\Request;
use Slim\Psr7\Response;
use SplFileInfo;
use Symfony\Contracts\Translation\TranslatorInterface;
class FileInfoHandler
{
@@ -17,16 +18,24 @@ class FileInfoHandler
/** @var Config App configuration component */
protected $config;
/** @var TranslatorInterface Translator component */
protected $translator;
/**
* Create a new FileInfoHandler object.
*
* @param \DI\Container $container
* @param \PHLAK\Config\Config $config
* @param \DI\Container $container
* @param \PHLAK\Config\Config $config
* @param \Symfony\Contracts\Translation\TranslatorInterface $translator
*/
public function __construct(Container $container, Config $config)
{
public function __construct(
Container $container,
Config $config,
TranslatorInterface $translator
) {
$this->container = $container;
$this->config = $config;
$this->translator = $translator;
}
/**
@@ -46,11 +55,11 @@ class FileInfoHandler
);
if (! $file->isFile()) {
return $response->withStatus(404, 'File not found');
return $response->withStatus(404, $this->translator->trans('error.file_not_found'));
}
if ($file->getSize() >= $this->config->get('app.max_hash_size', 1000000000)) {
return $response->withStatus(500, 'File size too large');
return $response->withStatus(500, $this->translator->trans('error.file_size_exceeded'));
}
$response->getBody()->write(json_encode([

View File

@@ -7,6 +7,8 @@ use Slim\Psr7\Request;
use Slim\Psr7\Response;
use Slim\Views\Twig;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Translation\Translator;
use Symfony\Contracts\Translation\TranslatorInterface;
class SearchHandler
{
@@ -16,16 +18,21 @@ class SearchHandler
/** @var Twig Twig templating component */
protected $view;
/** @var TranslatorInterface Translator component */
protected $translator;
/**
* Create a new SearchHandler object.
*
* @param \Symfony\Component\Finder\Finder $finder
* @param \Slim\Views\Twig $view
* @param \Symfony\Component\Finder\Finder $finder
* @param \Slim\Views\Twig $view
* @param \Symfony\Contracts\Translation\TranslatorInterface $translator
*/
public function __construct(Finder $finder, Twig $view)
public function __construct(Finder $finder, Twig $view, TranslatorInterface $translator)
{
$this->finder = $finder;
$this->view = $view;
$this->translator = $translator;
}
/**
@@ -42,7 +49,7 @@ class SearchHandler
if (empty($search)) {
return $this->view->render($response, 'error.twig', [
'message' => 'No results found'
'message' => $this->translator->trans('error.no_results_found')
]);
}

View File

@@ -10,6 +10,7 @@ use Slim\Psr7\Request;
use Slim\Psr7\Response;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tightenco\Collect\Support\Collection;
use ZipArchive;
@@ -24,17 +25,25 @@ class ZipHandler
/** @var Finder The Finder Component */
protected $finder;
/** @var TranslatorInterface Translator component */
protected $translator;
/**
* Create a new ZipHandler object.
*
* @param \DI\Container $container
* @param \PhpCsFixer\Finder $finder
*/
public function __construct(Container $container, Config $config, Finder $finder)
{
public function __construct(
Container $container,
Config $config,
Finder $finder,
TranslatorInterface $translator
) {
$this->container = $container;
$this->config = $config;
$this->finder = $finder;
$this->translator = $translator;
}
/**
@@ -50,7 +59,7 @@ class ZipHandler
$path = $request->getQueryParams()['zip'];
if (! $this->config->get('app.zip_downloads', true) || ! realpath($path)) {
return $response->withStatus(404, 'File not found');
return $response->withStatus(404, $this->translator->trans('error.file_not_found'));
}
$zip = new ZipArchive;

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Providers;
use DI\Container;
use Illuminate\Support\Collection;
use PHLAK\Config\Config;
use RuntimeException;
use Symfony\Component\Translation\Loader\YamlFileLoader;
use Symfony\Component\Translation\Translator;
use Symfony\Contracts\Translation\TranslatorInterface;
class TranslationProvider
{
/** @const Available translation languages */
protected const LANGUAGES = [
'de', 'en', 'es', 'fr', 'zh'
];
/** @var Container The applicaiton container */
protected $container;
/** @var Config The application config */
protected $config;
/**
* Create a new TranslationProvider object.
*
* @param \DI\Container $container
* @param \PHLAK\Config\Config $config
*/
public function __construct(Container $container, Config $config)
{
$this->container = $container;
$this->config = $config;
}
/**
* Initialize and register the translation component.
*
* @return void
*/
public function __invoke(): void
{
$language = $this->config->get('app.language', 'en');
if (! in_array($language, self::LANGUAGES)) {
throw new RuntimeException("Invalid language option '{$language}'");
}
$translator = new Translator($language);
$translator->addLoader('yaml', new YamlFileLoader());
Collection::make(self::LANGUAGES)->each(
function (string $language) use ($translator): void {
$resource = sprintf('app/translations/%s.yaml', $language);
$translator->addResource('yaml', $resource, $language);
}
);
$this->container->set(TranslatorInterface::class, $translator);
}
}

View File

@@ -22,6 +22,7 @@ class TwigProvider
ViewFunctions\Markdown::class,
ViewFunctions\ParentDir::class,
ViewFunctions\SizeForHumans::class,
ViewFunctions\Translate::class,
ViewFunctions\Url::class,
];

View File

@@ -0,0 +1,36 @@
<?php
namespace App\ViewFunctions;
use Symfony\Contracts\Translation\TranslatorInterface;
class Translate extends ViewFunction
{
/** @var string The function name */
protected $name = 'translate';
/** @var TranslatorInterface The application translator */
protected $translator;
/**
* Create a new Translate object.
*
* @param \Symfony\Contracts\Translation\TranslatorInterface $translator
*/
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
/**
* Retrieve a translated string by ID.
*
* @param string $id
*
* @return string
*/
public function __invoke(string $id): string
{
return $this->translator->trans($id);
}
}

19
app/translations/en.yaml Normal file
View File

@@ -0,0 +1,19 @@
home: Home
download: Download this Directory
search: Search
file:
name: File Name
size: Size
date: Date
info: File Info
powered_by: Powered by
scroll_to_top: Scroll to Top
error:
directory_not_found: Directory does not exist
file_not_found: File not found
file_size_exceeded: File size too large
no_results_found: No results found
unexpected: An unexpected error occurred
enable_debugging: Enable debugging for additional information

19
app/translations/es.yaml Normal file
View File

@@ -0,0 +1,19 @@
home: Hogar
download: Descargar este Directorio
search: Buscar
file:
name: Nombre del Archivo
size: Tamaño
date: Fecha
info: Información del Archivo
powered_by: Desarrollado por
scroll_to_top: Vuelve al Comienzo
error:
directory_not_found: El directorio no existe
file_not_found: Archivo no encontrado
file_size_exceeded: Tamaño de archivo demasiado grande
no_results_found: No se han encontrado resultados
unexpected: Ocurrió un error inesperado
enable_debugging: Habilite la depuración para obtener información adicional

19
app/translations/fr.yaml Normal file
View File

@@ -0,0 +1,19 @@
home: Accueil
download: Téléchargez ce Répertoire
search: Chercher
file:
name: Nom de Fichier
size: Taille
date: Date
info: Informations sur le Fichier
powered_by: Alimenté par
scroll_to_top: Faire Défiler vers le Haut
error:
directory_not_found: Le répertoire n'existe pas
file_not_found: Fichier non trouvé
file_size_exceeded: Taille de fichier trop grande
no_results_found: Aucun résultat trouvé
unexpected: Une erreur inattendue est apparue
enable_debugging: Activer le débogage pour des informations supplémentaires

19
app/translations/zh.yaml Normal file
View File

@@ -0,0 +1,19 @@
home:
download: 下载此目录
search: 搜索
file:
name: 文件名
size: 尺寸
date: 日期
info: 文件信息
powered_by: 供电
scroll_to_top: 滚动到顶部
error:
directory_not_found: 目录不存在
file_not_found: 文件未找到
file_size_exceeded: 档案太大
no_results_found: 未找到结果
unexpected: 一个意料之外的问题发生了
enable_debugging: 启用调试以获取其他信息

View File

@@ -18,7 +18,7 @@
{% if file.isFile %}
<div class="ml-2">
<button
title="File Info"
title="{{ translate('file.info') }}"
class="flex justify-center items-center rounded-full p-2 -m-1 md:invisible hover:bg-gray-400 hover:shadow group-hover:visible"
v-on:click.prevent="showFileInfo('{{ file.getPathname | escape('js') }}')"
>

View File

@@ -1,7 +1,7 @@
<footer class="container border-t-2 border-gray-800 text-center mx-auto px-4 py-8">
<div class="flex flex-col justify-center items-center">
<p class="mb-4">
Powered by <a href="https://www.directorylister.com" class="underline hover:text-blue-700">Directory Lister</a>
{{ translate('powered_by') }} <a href="https://www.directorylister.com" class="underline hover:text-blue-700">Directory Lister</a>
</p>
<div class="flex">

View File

@@ -1,7 +1,9 @@
<header id="header" class="bg-blue-600 shadow sticky top-0">
<div class="container flex flex-col flex-coljustify-between items-center mx-auto p-4 md:flex-row">
<div class="flex-grow font-mono text-white text-sm tracking-tight mb-2 md:my-1">
<a href="." class="hover:underline">Home</a>
<a href="." class="hover:underline">
{{ translate('home') }}
</a>
{% if path %}
{% for name, path in breadcrumbs(path) %}
@@ -12,14 +14,14 @@
<div class="flex justify-end items-center">
{% if path and config('zip_downloads', true) %}
<a href="?zip={{ path }}" title="Download this Directory" class="inline-block text-white mx-2 p-1 hover:text-gray-400">
<a href="?zip={{ path }}" title="{{ translate('download') }}" class="inline-block text-white mx-2 p-1 hover:text-gray-400">
<i class="fas fa-download fa-lg"></i>
</a>
{% endif %}
<form action="." method="get" id="search" class="flex-grow group relative block bg-blue-700 rounded-full shadow-inner">
<input v-model="search" ref="searchInput" v-on:focus="$event.target.select()"
type="text" name="search" placeholder="Search..." value="{{ search }}"
type="text" name="search" placeholder="{{ translate('search') }}..." value="{{ search }}"
class="bg-transparent placeholder-gray-900 text-white w-full px-10 py-2"
>

View File

@@ -1,8 +1,8 @@
<div class="fixed bottom-0 left-0 right-0 pointer-events-none">
<div class="container flex justify-end mx-auto px-4 py-10">
<button id="scroll-to-top" ref="scrollToTop"
<button id="scroll-to-top" ref="scrollToTop" title="{{ translate('scroll_to_top') }}"
class="flex justify-center items-center w-12 h-12 right-0 rounded-full shadow-lg bg-blue-600 text-white cursor-pointer pointer-events-auto hover:bg-blue-700 hidden"
onclick="window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });" title="Scroll to Top"
onclick="window.scrollTo({ top: 0, left: 0, behavior: 'smooth' });"
>
<i class="fas fa-arrow-up fa-lg"></i>
</button>

View File

@@ -7,15 +7,15 @@
<div class="my-4">
<div class="flex justify-between font-bold p-4">
<div class="flex-grow font-mono mr-2">
File Name
{{ translate('file.name') }}
</div>
<div class="font-mono text-right w-1/6 mx-2 hidden sm:block">
Size
{{ translate('file.size') }}
</div>
<div class="font-mono text-right w-1/4 ml-2 hidden sm:block">
Date
{{ translate('file.date') }}
</div>
</div>

View File

@@ -23,6 +23,7 @@
"slim/slim": "^4.3",
"slim/twig-view": "^3.0",
"symfony/finder": "^5.0",
"symfony/translation": "^5.0",
"tightenco/collect": "^6.4",
"vlucas/phpdotenv": "^4.0"
},

136
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "1a4f0a5fb5a91dc494cb5479886f6001",
"content-hash": "ec21efdea1e0689436e9653f81e1c18c",
"packages": [
{
"name": "erusev/parsedown",
@@ -1690,6 +1690,140 @@
],
"time": "2020-01-13T11:15:53+00:00"
},
{
"name": "symfony/translation",
"version": "v5.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "28e1054f1ea26c63762d9260c37cb1056ea62dbb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/28e1054f1ea26c63762d9260c37cb1056ea62dbb",
"reference": "28e1054f1ea26c63762d9260c37cb1056ea62dbb",
"shasum": ""
},
"require": {
"php": "^7.2.5",
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation-contracts": "^2"
},
"conflict": {
"symfony/config": "<4.4",
"symfony/dependency-injection": "<5.0",
"symfony/http-kernel": "<5.0",
"symfony/twig-bundle": "<5.0",
"symfony/yaml": "<4.4"
},
"provide": {
"symfony/translation-implementation": "2.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "^4.4|^5.0",
"symfony/console": "^4.4|^5.0",
"symfony/dependency-injection": "^5.0",
"symfony/finder": "^4.4|^5.0",
"symfony/http-kernel": "^5.0",
"symfony/intl": "^4.4|^5.0",
"symfony/service-contracts": "^1.1.2|^2",
"symfony/yaml": "^4.4|^5.0"
},
"suggest": {
"psr/log-implementation": "To use logging capability in translator",
"symfony/config": "",
"symfony/yaml": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Translation\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
"time": "2020-01-21T08:40:24+00:00"
},
{
"name": "symfony/translation-contracts",
"version": "v2.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
"reference": "8cc682ac458d75557203b2f2f14b0b92e1c744ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/8cc682ac458d75557203b2f2f14b0b92e1c744ed",
"reference": "8cc682ac458d75557203b2f2f14b0b92e1c744ed",
"shasum": ""
},
"require": {
"php": "^7.2.5"
},
"suggest": {
"symfony/translation-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Translation\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to translation",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"time": "2019-11-18T17:27:11+00:00"
},
{
"name": "symfony/var-dumper",
"version": "v5.0.4",

View File

@@ -11,10 +11,19 @@ use Tests\TestCase;
class ErrorHandlerTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
$this->container->call(TwigProvider::class);
}
public function test_it_returns_an_error(): void
{
$this->container->call(TwigProvider::class);
$errorHandler = new ErrorHandler($this->container->get(Twig::class));
$errorHandler = new ErrorHandler(
$this->container->get(Twig::class),
$this->translator
);
$response = $errorHandler(
$this->createMock(Request::class),
@@ -32,8 +41,10 @@ class ErrorHandlerTest extends TestCase
public function test_it_returns_an_error_for_a_json_request(): void
{
$this->container->call(TwigProvider::class);
$errorHandler = new ErrorHandler($this->container->get(Twig::class));
$errorHandler = new ErrorHandler(
$this->container->get(Twig::class),
$this->translator
);
$request = $this->createMock(Request::class);
$request->expects($this->once())->method('getHeaderLine')->willReturn(
@@ -50,7 +61,7 @@ class ErrorHandlerTest extends TestCase
$this->assertEquals(500, $response->getStatusCode());
$this->assertEquals('application/json', $response->getHeaderLine('Content-Type'));
$this->assertEquals('An unexpected error occured', json_decode(
$this->assertEquals('An unexpected error occurred', json_decode(
(string) $response->getBody()
)->error->message);
}

View File

@@ -28,7 +28,8 @@ class DirectoryHandlerTest extends TestCase
$controller = new DirectoryHandler(
$this->config,
new Finder,
$this->container->get(Twig::class)
$this->container->get(Twig::class),
$this->translator
);
chdir($this->filePath('.'));
@@ -53,7 +54,8 @@ class DirectoryHandlerTest extends TestCase
$controller = new DirectoryHandler(
$this->config,
new Finder,
$this->container->get(Twig::class)
$this->container->get(Twig::class),
$this->translator
);
$request = $this->createMock(Request::class);
@@ -73,7 +75,8 @@ class DirectoryHandlerTest extends TestCase
$controller = new DirectoryHandler(
$this->config,
new Finder,
$this->container->get(Twig::class)
$this->container->get(Twig::class),
$this->translator
);
$request = $this->createMock(Request::class);

View File

@@ -12,7 +12,7 @@ class FileInfoHandlerTest extends TestCase
{
public function test_it_can_return_a_successful_response(): void
{
$handler = new FileInfoHandler($this->container, $this->config);
$handler = new FileInfoHandler($this->container, $this->config, $this->translator);
$request = $this->createMock(Request::class);
$request->method('getQueryParams')->willReturn(['info' => 'README.md']);
@@ -32,7 +32,7 @@ class FileInfoHandlerTest extends TestCase
public function test_it_can_return_a_not_found_response(): void
{
$handler = new FileInfoHandler($this->container, $this->config);
$handler = new FileInfoHandler($this->container, $this->config, $this->translator);
$request = $this->createMock(Request::class);
$request->method('getQueryParams')->willReturn(['info' => 'not_a_file.test']);
@@ -46,7 +46,7 @@ class FileInfoHandlerTest extends TestCase
public function test_it_returns_an_error_when_file_size_is_too_large(): void
{
$this->config->set('app.max_hash_size', 10);
$handler = new FileInfoHandler($this->container, $this->config);
$handler = new FileInfoHandler($this->container, $this->config, $this->translator);
$request = $this->createMock(Request::class);
$request->method('getQueryParams')->willReturn(['info' => 'README.md']);

View File

@@ -13,7 +13,7 @@ class ZipHandlerTest extends TestCase
{
public function test_it_returns_a_successful_response_for_a_zip_request(): void
{
$handler = new ZipHandler($this->container, $this->config, new Finder);
$handler = new ZipHandler($this->container, $this->config, new Finder, $this->translator);
$request = $this->createMock(Request::class);
$request->method('getQueryParams')->willReturn(['zip' => 'subdir']);
@@ -30,7 +30,7 @@ class ZipHandlerTest extends TestCase
public function test_it_returns_a_404_error_when_not_found(): void
{
$handler = new ZipHandler($this->container, $this->config, new Finder);
$handler = new ZipHandler($this->container, $this->config, new Finder, $this->translator);
$request = $this->createMock(Request::class);
$request->method('getQueryParams')->willReturn(['zip' => '404']);
@@ -45,7 +45,7 @@ class ZipHandlerTest extends TestCase
public function test_it_returns_a_404_error_when_disabled_via_config(): void
{
$this->config->set('app.zip_downloads', false);
$handler = new ZipHandler($this->container, $this->config, new Finder);
$handler = new ZipHandler($this->container, $this->config, new Finder, $this->translator);
$request = $this->createMock(Request::class);
$request->method('getQueryParams')->willReturn(['zip' => 'subdir']);

View File

@@ -0,0 +1,31 @@
<?php
namespace Tests\Providers;
use App\Providers\TranslationProvider;
use RuntimeException;
use Symfony\Component\Translation\MessageCatalogue;
use Symfony\Contracts\Translation\TranslatorInterface;
use Tests\TestCase;
class TranslationProviderTest extends TestCase
{
public function test_it_registers_the_translation_component(): void
{
(new TranslationProvider($this->container, $this->config))();
$translator = $this->container->get(TranslatorInterface::class);
$this->assertEquals('en', $translator->getLocale());
$this->assertInstanceOf(MessageCatalogue::class, $translator->getCatalogue('en'));
$this->assertInstanceOf(MessageCatalogue::class, $translator->getCatalogue('fr'));
}
public function test_it_throws_an_exception_for_an_invalid_language(): void
{
$this->expectException(RuntimeException::class);
$this->config->set('app.language', 'xx');
(new TranslationProvider($this->container, $this->config))();
}
}

View File

@@ -5,6 +5,9 @@ namespace Tests;
use DI\Container;
use PHLAK\Config\Config;
use PHPUnit\Framework\TestCase as PHPUnitTestCase;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Translator;
use Symfony\Contracts\Translation\TranslatorInterface;
class TestCase extends PHPUnitTestCase
{
@@ -14,6 +17,9 @@ class TestCase extends PHPUnitTestCase
/** @var Config The test config */
protected $config;
/** @var TranslatorInterface Test translator */
protected $translator;
/** @var string Path to test files directory */
protected $testFilesPath = __DIR__ . '/_files';
@@ -28,6 +34,8 @@ class TestCase extends PHPUnitTestCase
$this->config = new Config([
'app' => [
'debug' => false,
'language' => 'en',
'dark_mode' => false,
'display_readmes' => true,
'zip_downloads' => true,
@@ -43,9 +51,34 @@ class TestCase extends PHPUnitTestCase
]
]);
$this->translator = new Translator('en');
$this->translator->addLoader('array', new ArrayLoader);
$this->translator->addResource('array', [
'home' => 'Home',
'download' => 'Download this Directory',
'search' => 'Search',
'file' => [
'name' => 'File Name',
'size' => 'Size',
'date' => 'Date',
'info' => 'File Info',
'powered_by' => 'Powered by',
'scroll_to_top' => 'Scroll to Top',
],
'error' => [
'directory_not_found' => 'Directory does not exist',
'file_not_found' => 'File not found',
'file_size_exceeded' => 'File size too large',
'no_results_found' => 'No results found',
'unexpected' => 'An unexpected error occurred',
],
'enable_debugging' => 'Enable debugging for additional information',
], 'en');
$this->container = new Container();
$this->container->set('base_path', $this->testFilesPath);
$this->container->set(Config::class, $this->config);
$this->container->set(TranslatorInterface::class, $this->translator);
}
/**

View File

@@ -0,0 +1,45 @@
<?php
namespace Tests\ViewFunctions;
use App\ViewFunctions\Translate;
use Symfony\Component\Translation\Loader\ArrayLoader;
use Symfony\Component\Translation\Translator;
use Tests\TestCase;
class TranslateTest extends TestCase
{
/** @var Translator Translator component */
protected $tranlator;
public function setUp(): void
{
parent::setUp();
$this->translator = new Translator('en');
$this->translator->addLoader('array', new ArrayLoader);
$this->translator->addResource('array', [
'foo' => 'Foo', 'bar' => ['baz' => 'Bar Baz'],
], 'en');
$this->translator->addResource('array', [
'foo' => 'Le Foo', 'bar' => ['baz' => 'Le Bar Baz'],
], 'fr');
}
public function test_it_can_get_a_translation_for_the_defualt_locale(): void
{
$translate = new Translate($this->translator);
$this->assertEquals('Foo', $translate('foo'));
$this->assertEquals('Bar Baz', $translate('bar.baz'));
}
public function test_it_can_get_a_translation_for_an_alternative_locale(): void
{
$this->translator->setLocale('fr');
$translate = new Translate($this->translator);
$this->assertEquals('Le Foo', $translate('foo'));
$this->assertEquals('Le Bar Baz', $translate('bar.baz'));
}
}