Add Internationalization
- Add Utils/L10n class - Add translator functions to PHP Renderer - Refactor web controllers to prevent duplicated code - Add locale middleware - Add translation file loading - Add i18n settings
This commit is contained in:
parent
13a2068a8b
commit
5b7bb030de
|
@ -1,141 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Content;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class L10n
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $lang;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $strings;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $lang_path;
|
||||
|
||||
public function __construct(string $language = 'en', string $lang_path = '')
|
||||
{
|
||||
$this->lang = $language;
|
||||
$this->lang_path = $lang_path;
|
||||
|
||||
$this->loadTranslationTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads string translation table
|
||||
*
|
||||
* First addon strings are loaded, then globals
|
||||
*
|
||||
* Uses an App object shim since all the strings files refer to $a->strings
|
||||
*
|
||||
* @param string $lang language code to load
|
||||
*/
|
||||
private function loadTranslationTable(): void
|
||||
{
|
||||
if (file_exists($this->lang_path . '/' . $this->lang . '/strings.php')) {
|
||||
$this->strings = include $this->lang_path . '/' . $this->lang . '/strings.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the localized version of a singular/plural string with optional string interpolation
|
||||
*
|
||||
* This function takes two english strings as parameters, singular and plural, as
|
||||
* well as a count. If a localized version exists for the current language, they
|
||||
* are used instead. Discrimination between singular and plural is done using the
|
||||
* localized function if any or the default one. Finally, a string interpolation
|
||||
* is performed using the count as parameter.
|
||||
*
|
||||
* Usages:
|
||||
* - L10n::tt('Like', 'Likes', $count)
|
||||
* - L10n::tt("%s user deleted", "%s users deleted", count($users))
|
||||
*
|
||||
* @param string $singular
|
||||
* @param string $plural
|
||||
* @param int $count
|
||||
* @return string
|
||||
*/
|
||||
public function tt(string $singular, string $plural, int $count): string
|
||||
{
|
||||
if (!empty($this->strings[$singular])) {
|
||||
$t = $this->strings[$singular];
|
||||
if (is_array($t)) {
|
||||
$plural_function = 'string_plural_select_' . str_replace('-', '_', $this->lang);
|
||||
if (function_exists($plural_function)) {
|
||||
$i = $plural_function($count);
|
||||
} else {
|
||||
$i = $this->stringPluralSelectDefault($count);
|
||||
}
|
||||
|
||||
// for some languages there is only a single array item
|
||||
if (!isset($t[$i])) {
|
||||
$s = $t[0];
|
||||
} else {
|
||||
$s = $t[$i];
|
||||
}
|
||||
} else {
|
||||
$s = $t;
|
||||
}
|
||||
} elseif ($this->stringPluralSelectDefault($count)) {
|
||||
$s = $plural;
|
||||
} else {
|
||||
$s = $singular;
|
||||
}
|
||||
|
||||
$s = @sprintf($s, $count);
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the localized version of the provided string with optional string interpolation
|
||||
*
|
||||
* This function takes a english string as parameter, and if a localized version
|
||||
* exists for the current language, substitutes it before performing an eventual
|
||||
* string interpolation (sprintf) with additional optional arguments.
|
||||
*
|
||||
* Usages:
|
||||
* - L10n::t('This is an example')
|
||||
* - L10n::t('URL %s returned no result', $url)
|
||||
* - L10n::t('Current version: %s, new version: %s', $current_version, $new_version)
|
||||
*
|
||||
* @param string $s
|
||||
* @param array $vars Variables to interpolate in the translation string
|
||||
* @return string
|
||||
*/
|
||||
public function t($s, ...$vars): string
|
||||
{
|
||||
if (empty($s)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!empty($this->strings[$s])) {
|
||||
$t = $this->strings[$s];
|
||||
$s = is_array($t) ? $t[0] : $t;
|
||||
}
|
||||
|
||||
if (count($vars) > 0) {
|
||||
$s = sprintf($s, ...$vars);
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a fallback which will not collide with a function defined in any language file
|
||||
*/
|
||||
private function stringPluralSelectDefault(int $n): bool
|
||||
{
|
||||
return $n != 1;
|
||||
}
|
||||
|
||||
}
|
|
@ -24,7 +24,7 @@ class Pager
|
|||
private $baseQueryString = '';
|
||||
|
||||
/**
|
||||
* @var \Friendica\Directory\Content\L10n
|
||||
* @var \Gettext\TranslatorInterface
|
||||
*/
|
||||
private $l10n;
|
||||
|
||||
|
@ -33,11 +33,11 @@ class Pager
|
|||
*
|
||||
* Guesses the page number from the GET parameter 'page'.
|
||||
*
|
||||
* @param \Friendica\Directory\Content\L10n $l10n
|
||||
* @param \Gettext\TranslatorInterface $l10n
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param integer $itemsPerPage An optional number of items per page to override the default value
|
||||
*/
|
||||
public function __construct(L10n $l10n, \Psr\Http\Message\ServerRequestInterface $request, int $itemsPerPage = 50)
|
||||
public function __construct(\Gettext\TranslatorInterface $l10n, \Psr\Http\Message\ServerRequestInterface $request, int $itemsPerPage = 50)
|
||||
{
|
||||
$this->l10n = $l10n;
|
||||
$this->setQueryString($request);
|
||||
|
@ -157,7 +157,7 @@ class Pager
|
|||
* @param integer $itemCount The number of displayed items on the page
|
||||
* @return array of links
|
||||
*/
|
||||
public function renderMinimal(int $itemCount, string $previous_label = 'Previous', string $next_label = 'Next')
|
||||
public function renderMinimal(int $itemCount)
|
||||
{
|
||||
$displayedItemCount = max(0, $itemCount);
|
||||
|
||||
|
@ -165,12 +165,12 @@ class Pager
|
|||
'class' => 'pager',
|
||||
'prev' => [
|
||||
'url' => $this->ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() - 1)),
|
||||
'text' => $this->l10n->t($previous_label),
|
||||
'text' => $this->l10n->gettext('Previous'),
|
||||
'class' => 'previous' . ($this->getPage() == 1 ? ' disabled' : '')
|
||||
],
|
||||
'next' => [
|
||||
'url' => $this->ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)),
|
||||
'text' => $this->l10n->t($next_label),
|
||||
'text' => $this->l10n->gettext('Next'),
|
||||
'class' => 'next' . ($displayedItemCount <= 0 ? ' disabled' : '')
|
||||
]
|
||||
];
|
||||
|
@ -208,12 +208,12 @@ class Pager
|
|||
if ($totalItemCount > $this->getItemsPerPage()) {
|
||||
$data['first'] = [
|
||||
'url' => $this->ensureQueryParameter($this->baseQueryString . '&page=1'),
|
||||
'text' => $this->l10n->t('First'),
|
||||
'text' => $this->l10n->gettext('First'),
|
||||
'class' => $this->getPage() == 1 ? 'disabled' : ''
|
||||
];
|
||||
$data['prev'] = [
|
||||
'url' => $this->ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() - 1)),
|
||||
'text' => $this->l10n->t('Previous'),
|
||||
'text' => $this->l10n->gettext('Previous'),
|
||||
'class' => $this->getPage() == 1 ? 'disabled' : ''
|
||||
];
|
||||
|
||||
|
@ -270,12 +270,12 @@ class Pager
|
|||
|
||||
$data['next'] = [
|
||||
'url' => $this->ensureQueryParameter($this->baseQueryString . '&page=' . ($this->getPage() + 1)),
|
||||
'text' => $this->l10n->t('Next'),
|
||||
'text' => $this->l10n->gettext('Next'),
|
||||
'class' => $this->getPage() == $lastpage ? 'disabled' : ''
|
||||
];
|
||||
$data['last'] = [
|
||||
'url' => $this->ensureQueryParameter($this->baseQueryString . '&page=' . $lastpage),
|
||||
'text' => $this->l10n->t('Last'),
|
||||
'text' => $this->l10n->gettext('Last'),
|
||||
'class' => $this->getPage() == $lastpage ? 'disabled' : ''
|
||||
];
|
||||
}
|
||||
|
|
|
@ -21,14 +21,14 @@ class Search
|
|||
*/
|
||||
private $profileModel;
|
||||
/**
|
||||
* @var \Friendica\Directory\Content\L10n
|
||||
* @var \Gettext\TranslatorInterface
|
||||
*/
|
||||
private $l10n;
|
||||
|
||||
public function __construct(
|
||||
\Atlas\Pdo\Connection $atlas,
|
||||
\Friendica\Directory\Models\Profile $profileModel,
|
||||
\Friendica\Directory\Content\L10n $l10n
|
||||
\Gettext\TranslatorInterface $l10n
|
||||
)
|
||||
{
|
||||
$this->atlas = $atlas;
|
||||
|
@ -67,6 +67,7 @@ AND `account_type` = :account_type';
|
|||
|
||||
$vars = [
|
||||
'query' => $originalQuery,
|
||||
'field' => $field,
|
||||
'page' => $pager->getPage(),
|
||||
'itemsperpage' => $pager->getItemsPerPage(),
|
||||
'count' => $count,
|
||||
|
|
9
src/classes/Controllers/Web/BaseController.php
Normal file
9
src/classes/Controllers/Web/BaseController.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Controllers\Web;
|
||||
|
||||
|
||||
abstract class BaseController
|
||||
{
|
||||
|
||||
}
|
|
@ -2,17 +2,17 @@
|
|||
|
||||
namespace Friendica\Directory\Controllers\Web;
|
||||
|
||||
use \Friendica\Directory\Content\Pager;
|
||||
use \Friendica\Directory\Views\Widget\PopularCountries;
|
||||
use \Friendica\Directory\Views\Widget\PopularTags;
|
||||
use PDO;
|
||||
use Friendica\Directory\Content\Pager;
|
||||
use Friendica\Directory\Views\Widget\PopularCountries;
|
||||
use Friendica\Directory\Views\Widget\PopularLanguages;
|
||||
use Friendica\Directory\Views\Widget\PopularTags;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Directory
|
||||
class Directory extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var \Atlas\Pdo\Connection
|
||||
|
@ -31,7 +31,7 @@ class Directory
|
|||
*/
|
||||
private $renderer;
|
||||
/**
|
||||
* @var \Friendica\Directory\Content\L10n
|
||||
* @var \Gettext\TranslatorInterface
|
||||
*/
|
||||
private $l10n;
|
||||
|
||||
|
@ -40,7 +40,7 @@ class Directory
|
|||
\Friendica\Directory\Models\Profile $profileModel,
|
||||
\Friendica\Directory\Views\Widget\AccountTypeTabs $accountTypeTabs,
|
||||
\Friendica\Directory\Views\PhpRenderer $renderer,
|
||||
\Friendica\Directory\Content\L10n $l10n
|
||||
\Gettext\TranslatorInterface $l10n
|
||||
)
|
||||
{
|
||||
$this->atlas = $atlas;
|
||||
|
@ -50,10 +50,11 @@ class Directory
|
|||
$this->l10n = $l10n;
|
||||
}
|
||||
|
||||
public function render(Request $request, Response $response, array $args): Response
|
||||
public function render(Request $request, Response $response, array $args): array
|
||||
{
|
||||
$popularTags = new PopularTags($this->atlas, $this->renderer);
|
||||
$popularCountries = new PopularCountries($this->atlas, $this->renderer);
|
||||
$popularLanguages = new PopularLanguages($this->atlas, $this->renderer);
|
||||
|
||||
$pager = new Pager($this->l10n, $request, 20);
|
||||
|
||||
|
@ -69,18 +70,19 @@ class Directory
|
|||
$count = $this->profileModel->getCountForDisplay($condition, $values);
|
||||
|
||||
$vars = [
|
||||
'title' => $this->l10n->t('People'),
|
||||
'title' => $this->l10n->gettext('People'),
|
||||
'profiles' => $profiles,
|
||||
'pager_full' => $pager->renderFull($count),
|
||||
'pager_minimal' => $pager->renderMinimal($count),
|
||||
'accountTypeTabs' => $this->accountTypeTabs->render('directory', $args['account_type'] ?? ''),
|
||||
'popularTags' => $popularTags->render(),
|
||||
'popularCountries' => $popularCountries->render(),
|
||||
'popularLanguages' => $popularLanguages->render(),
|
||||
];
|
||||
|
||||
$content = $this->renderer->fetch('directory.phtml', $vars);
|
||||
|
||||
// Render index view
|
||||
return $this->renderer->render($response, 'layout.phtml', ['baseUrl' => $request->getUri()->getBaseUrl(), 'content' => $content]);
|
||||
return ['content' => $content];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use Psr\Http\Message\ServerRequestInterface;
|
|||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Search
|
||||
class Search extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var \Atlas\Pdo\Connection
|
||||
|
@ -29,7 +29,7 @@ class Search
|
|||
*/
|
||||
private $accountTypeTabs;
|
||||
/**
|
||||
* @var \Friendica\Directory\Content\L10n
|
||||
* @var \Gettext\TranslatorInterface
|
||||
*/
|
||||
private $l10n;
|
||||
|
||||
|
@ -38,7 +38,7 @@ class Search
|
|||
\Friendica\Directory\Models\Profile $profileModel,
|
||||
\Friendica\Directory\Views\Widget\AccountTypeTabs $accountTypeTabs,
|
||||
\Friendica\Directory\Views\PhpRenderer $renderer,
|
||||
\Friendica\Directory\Content\L10n $l10n
|
||||
\Gettext\TranslatorInterface $l10n
|
||||
)
|
||||
{
|
||||
$this->atlas = $atlas;
|
||||
|
@ -48,7 +48,7 @@ class Search
|
|||
$this->l10n = $l10n;
|
||||
}
|
||||
|
||||
public function render(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args): \Slim\Http\Response
|
||||
public function render(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args): array
|
||||
{
|
||||
$pager = new Pager($this->l10n, $request, 20);
|
||||
|
||||
|
@ -56,9 +56,20 @@ class Search
|
|||
|
||||
$field = filter_input(INPUT_GET, 'field', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW & FILTER_FLAG_STRIP_HIGH);
|
||||
|
||||
$fieldName = '';
|
||||
|
||||
if ($field) {
|
||||
$query .= '%';
|
||||
$sql_where = '`' . $field . '` LIKE :query';
|
||||
$sql_where = 'p.`' . $field . '` LIKE :query';
|
||||
|
||||
switch($field) {
|
||||
case 'language': $fieldName = $this->l10n->pgettext('field', 'Language'); break;
|
||||
case 'locality': $fieldName = $this->l10n->pgettext('field', 'Locality'); break;
|
||||
case 'region' : $fieldName = $this->l10n->pgettext('field', 'Region') ; break;
|
||||
case 'country' : $fieldName = $this->l10n->pgettext('field', 'Country') ; break;
|
||||
default: $fieldName = ucfirst($field);
|
||||
}
|
||||
|
||||
} else {
|
||||
$sql_where = "MATCH (p.`name`, p.`pdesc`, p.`profile_url`, p.`locality`, p.`region`, p.`country`, p.`tags` )
|
||||
AGAINST (:query IN BOOLEAN MODE)";
|
||||
|
@ -79,8 +90,10 @@ AND `account_type` = :account_type';
|
|||
|
||||
$vars = [
|
||||
'query' => $originalQuery,
|
||||
'field' => $field,
|
||||
'fieldName' => $fieldName,
|
||||
'count' => $count,
|
||||
'accountTypeTabs' => $this->accountTypeTabs->render('search', $account_type, ['q' => $originalQuery]),
|
||||
'accountTypeTabs' => $this->accountTypeTabs->render('search', $account_type, ['q' => $originalQuery, 'field' => $field]),
|
||||
'profiles' => $profiles,
|
||||
'pager_full' => $pager->renderFull($count),
|
||||
'pager_minimal' => $pager->renderMinimal($count),
|
||||
|
@ -89,6 +102,6 @@ AND `account_type` = :account_type';
|
|||
$content = $this->renderer->fetch('search.phtml', $vars);
|
||||
|
||||
// Render index view
|
||||
return $this->renderer->render($response, 'layout.phtml', ['baseUrl' => $request->getUri()->getBaseUrl(), 'content' => $content, 'noNavSearch' => true]);
|
||||
return ['content' => $content, 'noNavSearch' => true];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use Slim\Http\Response;
|
|||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Servers
|
||||
class Servers extends BaseController
|
||||
{
|
||||
/**
|
||||
* @var \Atlas\Pdo\Connection
|
||||
|
@ -21,7 +21,7 @@ class Servers
|
|||
*/
|
||||
private $renderer;
|
||||
/**
|
||||
* @var \Friendica\Directory\Content\L10n
|
||||
* @var \Gettext\TranslatorInterface
|
||||
*/
|
||||
private $l10n;
|
||||
/**
|
||||
|
@ -32,7 +32,7 @@ class Servers
|
|||
public function __construct(
|
||||
\Atlas\Pdo\Connection $atlas,
|
||||
\Friendica\Directory\Views\PhpRenderer $renderer,
|
||||
\Friendica\Directory\Content\L10n $l10n,
|
||||
\Gettext\TranslatorInterface $l10n,
|
||||
\Psr\SimpleCache\CacheInterface $simplecache
|
||||
)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ class Servers
|
|||
$this->simplecache = $simplecache;
|
||||
}
|
||||
|
||||
public function render(Request $request, Response $response): Response
|
||||
public function render(Request $request, Response $response): array
|
||||
{
|
||||
$stable_version = $this->simplecache->get('stable_version');
|
||||
if (!$stable_version) {
|
||||
|
@ -72,7 +72,7 @@ LIMIT :start, :limit';
|
|||
|
||||
foreach ($servers as $key => $server) {
|
||||
$servers[$key]['user_count'] = $this->atlas->fetchValue(
|
||||
'SELECT COUNT(*) FROM `profile` WHERE `available` AND `server_id` = :server_id',
|
||||
'SELECT COUNT(*) FROM `profile` WHERE `available` AND NOT `hidden` AND `server_id` = :server_id',
|
||||
['server_id' => [$server['id'], PDO::PARAM_INT]]
|
||||
);
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ AND NOT `hidden`';
|
|||
$count = $this->atlas->fetchValue($stmt);
|
||||
|
||||
$vars = [
|
||||
'title' => $this->l10n->t('Public Servers'),
|
||||
'title' => $this->l10n->gettext('Public Servers'),
|
||||
'servers' => $servers,
|
||||
'pager' => $pager->renderFull($count),
|
||||
'stable_version' => $stable_version,
|
||||
|
@ -95,6 +95,6 @@ AND NOT `hidden`';
|
|||
$content = $this->renderer->fetch('servers.phtml', $vars);
|
||||
|
||||
// Render index view
|
||||
return $this->renderer->render($response, 'layout.phtml', ['baseUrl' => $request->getUri()->getBaseUrl(), 'content' => $content]);
|
||||
return ['content' => $content];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,22 +9,10 @@ class Search extends BaseRoute
|
|||
{
|
||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args): \Slim\Http\Response
|
||||
{
|
||||
if ($request->getAttribute('negotiation')->getMediaType() == 'application/json') {
|
||||
$controller = new \Friendica\Directory\Controllers\Api\Search(
|
||||
return (new \Friendica\Directory\Controllers\Api\Search(
|
||||
$this->container->atlas,
|
||||
$this->container->get('\Friendica\Directory\Models\Profile'),
|
||||
$this->container->l10n
|
||||
);
|
||||
} else {
|
||||
$controller = new \Friendica\Directory\Controllers\Web\Search(
|
||||
$this->container->atlas,
|
||||
$this->container->get('\Friendica\Directory\Models\Profile'),
|
||||
$this->container->get('\Friendica\Directory\Views\Widget\AccountTypeTabs'),
|
||||
$this->container->renderer,
|
||||
$this->container->l10n
|
||||
);
|
||||
}
|
||||
|
||||
return $controller->render($request, $response, $args);
|
||||
))->render($request, $response, $args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Routes\Http;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Servers extends BaseRoute
|
||||
{
|
||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args): \Slim\Http\Response
|
||||
{
|
||||
return (new \Friendica\Directory\Controllers\Web\Servers(
|
||||
$this->container->atlas,
|
||||
$this->container->renderer,
|
||||
$this->container->l10n,
|
||||
$this->container->simplecache)
|
||||
)->render($request, $response);
|
||||
}
|
||||
}
|
44
src/classes/Routes/Web/BaseRoute.php
Normal file
44
src/classes/Routes/Web/BaseRoute.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Routes\Web;
|
||||
|
||||
use Friendica\Directory\Controllers\Web\BaseController;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
abstract class BaseRoute
|
||||
{
|
||||
/**
|
||||
* @var \Slim\Container
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @var BaseController
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args): \Slim\Http\Response
|
||||
{
|
||||
$defaults = [
|
||||
'languages' => $this->container->settings['i18n']['locales'],
|
||||
'lang' => $request->getAttribute('locale'),
|
||||
'baseUrl' => $request->getUri()->getBaseUrl(),
|
||||
'content' => '',
|
||||
'noNavSearch' => false
|
||||
];
|
||||
|
||||
$values = $this->controller->render($request, $response, $args);
|
||||
|
||||
$values = $values + $defaults;
|
||||
|
||||
// Render index view
|
||||
return $this->container->renderer->render($response, 'layout.phtml', $values);
|
||||
}
|
||||
}
|
|
@ -1,20 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Routes\Http;
|
||||
namespace Friendica\Directory\Routes\Web;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Directory extends BaseRoute
|
||||
{
|
||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args): \Slim\Http\Response
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
return (new \Friendica\Directory\Controllers\Web\Directory(
|
||||
parent::__construct($container);
|
||||
|
||||
$this->controller = new \Friendica\Directory\Controllers\Web\Directory(
|
||||
$this->container->atlas,
|
||||
$this->container->get('\Friendica\Directory\Models\Profile'),
|
||||
$this->container->get('\Friendica\Directory\Views\Widget\AccountTypeTabs'),
|
||||
$this->container->renderer,
|
||||
$this->container->l10n)
|
||||
)->render($request, $response, $args);
|
||||
$this->container->l10n
|
||||
);
|
||||
}
|
||||
}
|
22
src/classes/Routes/Web/Search.php
Normal file
22
src/classes/Routes/Web/Search.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Routes\Web;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Search extends BaseRoute
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
|
||||
$this->controller = new \Friendica\Directory\Controllers\Web\Search(
|
||||
$this->container->atlas,
|
||||
$this->container->get('\Friendica\Directory\Models\Profile'),
|
||||
$this->container->get('\Friendica\Directory\Views\Widget\AccountTypeTabs'),
|
||||
$this->container->renderer,
|
||||
$this->container->l10n
|
||||
);
|
||||
}
|
||||
}
|
21
src/classes/Routes/Web/Servers.php
Normal file
21
src/classes/Routes/Web/Servers.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Routes\Web;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class Servers extends BaseRoute
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
|
||||
$this->controller = new \Friendica\Directory\Controllers\Web\Servers(
|
||||
$this->container->atlas,
|
||||
$this->container->renderer,
|
||||
$this->container->l10n,
|
||||
$this->container->simplecache
|
||||
);
|
||||
}
|
||||
}
|
165
src/classes/Utils/L10n.php
Normal file
165
src/classes/Utils/L10n.php
Normal file
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Utils;
|
||||
|
||||
use Gettext\Languages\Language;
|
||||
use Gettext\Translator;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class L10n
|
||||
{
|
||||
public static $languages = [
|
||||
'af' => 'Afrikaans',
|
||||
'ak' => 'Akan',
|
||||
'am' => 'አማርኛ',
|
||||
'ar' => 'العربية',
|
||||
'as' => 'অসমীয়া',
|
||||
'az' => 'Azərbaycan',
|
||||
'be' => 'Беларуская',
|
||||
'bg' => 'Български',
|
||||
'bm' => 'Bamanakan',
|
||||
'bn' => 'বাংলা',
|
||||
'bo' => 'བོད་སྐད་',
|
||||
'br' => 'Brezhoneg',
|
||||
'bs' => 'Bosanski',
|
||||
'ca' => 'Català',
|
||||
'cs' => 'Čeština',
|
||||
'cy' => 'Cymraeg',
|
||||
'da' => 'Dansk',
|
||||
'de' => 'Deutsch',
|
||||
'de_AT' => 'Österreichisches Deutsch',
|
||||
'de_CH' => 'Schweizer Hochdeutsch',
|
||||
'dz' => 'རྫོང་ཁ',
|
||||
'ee' => 'Eʋegbe',
|
||||
'el' => 'Ελληνικά',
|
||||
'en' => 'English',
|
||||
'en_AU' => 'Australian English',
|
||||
'en_CA' => 'Canadian English',
|
||||
'en_GB' => 'British English',
|
||||
'en_US' => 'American English',
|
||||
'eo' => 'Esperanto',
|
||||
'es' => 'Español',
|
||||
'es_ES' => 'Español De España',
|
||||
'es_MX' => 'Español De México',
|
||||
'et' => 'Eesti',
|
||||
'eu' => 'Euskara',
|
||||
'fa' => 'فارسی',
|
||||
'ff' => 'Pulaar',
|
||||
'fi' => 'Suomi',
|
||||
'fo' => 'Føroyskt',
|
||||
'fr' => 'Français',
|
||||
'fr_CA' => 'Français Canadien',
|
||||
'fr_CH' => 'Français Suisse',
|
||||
'fy' => 'West-Frysk',
|
||||
'ga' => 'Gaeilge',
|
||||
'gd' => 'Gàidhlig',
|
||||
'gl' => 'Galego',
|
||||
'gu' => 'ગુજરાતી',
|
||||
'gv' => 'Gaelg',
|
||||
'ha' => 'Hausa',
|
||||
'he' => 'עברית',
|
||||
'hi' => 'हिन्दी',
|
||||
'hr' => 'Hrvatski',
|
||||
'hu' => 'Magyar',
|
||||
'hy' => 'Հայերեն',
|
||||
'id' => 'Bahasa Indonesia',
|
||||
'ig' => 'Igbo',
|
||||
'ii' => 'ꆈꌠꉙ',
|
||||
'is' => 'Íslenska',
|
||||
'it' => 'Italiano',
|
||||
'ja' => '日本語',
|
||||
'ka' => 'ქართული',
|
||||
'ki' => 'Gikuyu',
|
||||
'kk' => 'Қазақ Тілі',
|
||||
'kl' => 'Kalaallisut',
|
||||
'km' => 'ខ្មែរ',
|
||||
'kn' => 'ಕನ್ನಡ',
|
||||
'ko' => '한국어',
|
||||
'ks' => 'کٲشُر',
|
||||
'kw' => 'Kernewek',
|
||||
'ky' => 'Кыргызча',
|
||||
'lb' => 'Lëtzebuergesch',
|
||||
'lg' => 'Luganda',
|
||||
'ln' => 'Lingála',
|
||||
'lo' => 'ລາວ',
|
||||
'lt' => 'Lietuvių',
|
||||
'lu' => 'Tshiluba',
|
||||
'lv' => 'Latviešu',
|
||||
'mg' => 'Malagasy',
|
||||
'mk' => 'Македонски',
|
||||
'ml' => 'മലയാളം',
|
||||
'mn' => 'Монгол',
|
||||
'mr' => 'मराठी',
|
||||
'ms' => 'Bahasa Melayu',
|
||||
'mt' => 'Malti',
|
||||
'my' => 'ဗမာ',
|
||||
'nb' => 'Norsk Bokmål',
|
||||
'nd' => 'Isindebele',
|
||||
'ne' => 'नेपाली',
|
||||
'nl' => 'Nederlands',
|
||||
'nl_BE' => 'Vlaams',
|
||||
'nn' => 'Nynorsk',
|
||||
'no' => 'Norsk',
|
||||
'om' => 'Oromoo',
|
||||
'or' => 'ଓଡ଼ିଆ',
|
||||
'os' => 'Ирон',
|
||||
'pa' => 'ਪੰਜਾਬੀ',
|
||||
'pl' => 'Polski',
|
||||
'ps' => 'پښتو',
|
||||
'pt' => 'Português',
|
||||
'pt_BR' => 'Português Do Brasil',
|
||||
'pt_PT' => 'Português Europeu',
|
||||
'qu' => 'Runasimi',
|
||||
'rm' => 'Rumantsch',
|
||||
'rn' => 'Ikirundi',
|
||||
'ro' => 'Română',
|
||||
'ro_MD' => 'Moldovenească',
|
||||
'ru' => 'Русский',
|
||||
'rw' => 'Kinyarwanda',
|
||||
'se' => 'Davvisámegiella',
|
||||
'sg' => 'Sängö',
|
||||
'sh' => 'Srpskohrvatski',
|
||||
'si' => 'සිංහල',
|
||||
'sk' => 'Slovenčina',
|
||||
'sl' => 'Slovenščina',
|
||||
'sn' => 'Chishona',
|
||||
'so' => 'Soomaali',
|
||||
'sq' => 'Shqip',
|
||||
'sr' => 'Српски',
|
||||
'sv' => 'Svenska',
|
||||
'sw' => 'Kiswahili',
|
||||
'ta' => 'தமிழ்',
|
||||
'te' => 'తెలుగు',
|
||||
'th' => 'ไทย',
|
||||
'ti' => 'ትግርኛ',
|
||||
'tl' => 'Tagalog',
|
||||
'to' => 'Lea Fakatonga',
|
||||
'tr' => 'Türkçe',
|
||||
'ug' => 'ئۇيغۇرچە',
|
||||
'uk' => 'Українська',
|
||||
'ur' => 'اردو',
|
||||
'uz' => 'Oʻzbekcha',
|
||||
'vi' => 'Tiếng Việt',
|
||||
'yi' => 'ייִדיש',
|
||||
'yo' => 'Èdè Yorùbá',
|
||||
'zh' => '中文',
|
||||
'zh_Hans' => '简体中文',
|
||||
'zh_Hant' => '繁體中文',
|
||||
'zu' => 'Isizulu',
|
||||
];
|
||||
|
||||
public static function langToString($lang)
|
||||
{
|
||||
$found = false;
|
||||
foreach(self::$languages as $key => $language) {
|
||||
if (strtolower($key) == strtolower(str_replace('-', '_', $lang))) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $found ? $language : $lang;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,21 @@ namespace Friendica\Directory\Views;
|
|||
* Zend-Escaper wrapper for Slim PHP Renderer
|
||||
*
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*
|
||||
* @method string escapeHtml(string $value)
|
||||
* @method string escapeHtmlAttr(string $value)
|
||||
* @method string escapeCss(string $value)
|
||||
* @method string escapeJs(string $value)
|
||||
* @method string escapeUrl(string $value)
|
||||
* @method string noop(string $original)
|
||||
* @method string gettext(string $original)
|
||||
* @method string ngettext(string $original, string $plural, string $value)
|
||||
* @method string dngettext(string $domain, string $original, string $plural, string $value)
|
||||
* @method string npgettext(string $context, string $original, string $plural, string $value)
|
||||
* @method string pgettext(string $context, string $original)
|
||||
* @method string dgettext(string $domain, string $original)
|
||||
* @method string dpgettext(string $domain, string $context, string $original)
|
||||
* @method string dnpgettext(string $domain, string $context, string $original, string $plural, string $value)
|
||||
*/
|
||||
class PhpRenderer extends \Slim\Views\PhpRenderer
|
||||
{
|
||||
|
@ -14,13 +29,13 @@ class PhpRenderer extends \Slim\Views\PhpRenderer
|
|||
*/
|
||||
private $escaper;
|
||||
/**
|
||||
* @var \Friendica\Directory\Content\L10n
|
||||
* @var \Gettext\TranslatorInterface
|
||||
*/
|
||||
private $l10n;
|
||||
|
||||
public function __construct(
|
||||
\Zend\Escaper\Escaper $escaper,
|
||||
\Friendica\Directory\Content\L10n $l10n,
|
||||
\Gettext\TranslatorInterface $l10n,
|
||||
string $templatePath = "",
|
||||
array $attributes = array()
|
||||
)
|
||||
|
@ -36,28 +51,106 @@ class PhpRenderer extends \Slim\Views\PhpRenderer
|
|||
return $this->escapeHtml($value);
|
||||
}
|
||||
|
||||
public function escapeHtml(string $value): string
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
return $this->escaper->escapeHtml($value);
|
||||
if (method_exists($this->escaper, $name)) {
|
||||
return $this->escaper->$name(...$arguments);
|
||||
} elseif (method_exists($this->l10n, $name)) {
|
||||
return $this->l10n->$name(...$arguments);
|
||||
} else {
|
||||
throw new \Exception('Unknown PhpRendere magic method: ' . $name);
|
||||
}
|
||||
}
|
||||
|
||||
public function escapeCss(string $value): string
|
||||
/**
|
||||
* Echoes the translation of a string.
|
||||
*
|
||||
* Loose copy of Gettext/gettext global __() function
|
||||
*
|
||||
* Usages:
|
||||
* - $this->__('Label')
|
||||
* - $this->__('Label %s', $value)
|
||||
*
|
||||
* @param $original
|
||||
* @param array $args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __($original, ...$args)
|
||||
{
|
||||
return $this->escaper->escapeCss($value);
|
||||
$text = $this->l10n->gettext($original);
|
||||
|
||||
if (!count($args)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
public function escapeJs(string $value): string
|
||||
{
|
||||
return $this->escaper->escapeJs($value);
|
||||
return is_array($args[0]) ? strtr($text, $args[0]) : vsprintf($text, $args);
|
||||
}
|
||||
|
||||
public function escapeHtmlAttr(string $value): string
|
||||
/**
|
||||
* Returns the translation of a string in a specific context.
|
||||
*
|
||||
* @param string $context
|
||||
* @param string $original
|
||||
*
|
||||
* @param array $args
|
||||
* @return string
|
||||
*/
|
||||
function p__($context, $original, ...$args)
|
||||
{
|
||||
return $this->escaper->escapeHtmlAttr($value);
|
||||
$text = $this->l10n->pgettext($context, $original);
|
||||
|
||||
if (!count($args)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
public function escapeUrl(string $value): string
|
||||
return is_array($args[0]) ? strtr($text, $args[0]) : vsprintf($text, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the translation of a string in a specific domain.
|
||||
*
|
||||
* @param string $domain
|
||||
* @param string $original
|
||||
*
|
||||
* @param array $args
|
||||
* @return string
|
||||
*/
|
||||
function d__($domain, $original, ...$args)
|
||||
{
|
||||
return $this->escaper->escapeUrl($value);
|
||||
$text = $this->l10n->dgettext($domain, $original);
|
||||
|
||||
if (!count($args)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
return is_array($args[0]) ? strtr($text, $args[0]) : vsprintf($text, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Echoes the singular/plural translation of a string.
|
||||
*
|
||||
* Loose copy of Gettext/gettext global n__() function
|
||||
*
|
||||
* Usages:
|
||||
* - $this->n__('Label', 'Labels', 3)
|
||||
* - $this->n__('%d Label for %s', '%d Labels for %s', 3, $value)
|
||||
*
|
||||
* @param string $original
|
||||
* @param string $plural
|
||||
* @param string $count
|
||||
* @param array $args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function n__($original, $plural, $count, ...$args)
|
||||
{
|
||||
$text = $this->l10n->ngettext($original, $plural, $count);
|
||||
|
||||
array_unshift($args, $count);
|
||||
|
||||
return is_array($args[1]) ? strtr($text, $args[1]) : vsprintf($text, $args);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
36
src/classes/Views/Widget/PopularLanguages.php
Normal file
36
src/classes/Views/Widget/PopularLanguages.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Friendica\Directory\Views\Widget;
|
||||
|
||||
/**
|
||||
* @author Hypolite Petovan <mrpetovan@gmail.com>
|
||||
*/
|
||||
class PopularLanguages
|
||||
{
|
||||
/**
|
||||
* @var \Atlas\Pdo\Connection
|
||||
*/
|
||||
private $connection;
|
||||
/**
|
||||
* @var \Friendica\Directory\Views\PhpRenderer
|
||||
*/
|
||||
private $renderer;
|
||||
|
||||
public function __construct(\Atlas\Pdo\Connection $connection, \Friendica\Directory\Views\PhpRenderer $renderer)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
$this->renderer = $renderer;
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$stmt = 'SELECT `language`, COUNT(*) AS `total` FROM `profile` WHERE `language` IS NOT NULL GROUP BY `language` ORDER BY COUNT(`language`) DESC LIMIT 10';
|
||||
$languages = $this->connection->fetchAll($stmt);
|
||||
|
||||
$vars = [
|
||||
'languages' => $languages
|
||||
];
|
||||
|
||||
return $this->renderer->fetch('widget/popularlanguages.phtml', $vars);
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@ use Interop\Container\ContainerInterface;
|
|||
// DIC configuration
|
||||
|
||||
// l10n
|
||||
$container['l10n'] = function (ContainerInterface $c): Friendica\Directory\Content\L10n {
|
||||
$settings = $c->get('settings')['l10n'];
|
||||
return new Friendica\Directory\Content\L10n($settings['language'] ?: 'en', $settings['lang_path'] ?: '');
|
||||
$container['l10n'] = function (ContainerInterface $c): Gettext\TranslatorInterface {
|
||||
$translator = new Gettext\Translator();
|
||||
return $translator;
|
||||
};
|
||||
|
||||
// simple cache
|
||||
|
|
|
@ -1,9 +1,40 @@
|
|||
<?php
|
||||
// Application middleware
|
||||
|
||||
// e.g: $app->add(new \Slim\Csrf\Guard);
|
||||
// configure middleware
|
||||
use Boronczyk\LocalizationMiddleware;
|
||||
|
||||
$app->add(new \Gofabian\Negotiation\NegotiationMiddleware([
|
||||
'accept' => ['text/html', 'application/json']
|
||||
]));
|
||||
|
||||
|
||||
$middleware = new LocalizationMiddleware(
|
||||
$container->get('settings')['i18n']['locales'],
|
||||
$container->get('settings')['i18n']['default']
|
||||
);
|
||||
|
||||
$middleware->setLocaleCallback(function (string $locale) use ($container) {
|
||||
$langPath = $container->get('settings')['i18n']['path'];
|
||||
|
||||
$translator = $container->get('l10n');
|
||||
if (is_a($translator, 'Gettext\GettextTranslator')) {
|
||||
// One of them will end up working, right?
|
||||
$translator->setLanguage($locale);
|
||||
$translator->setLanguage($locale . '.utf8');
|
||||
$translator->setLanguage($locale . '.UTF8');
|
||||
$translator->setLanguage($locale . '.utf-8');
|
||||
$translator->setLanguage($locale . '.UTF-8');
|
||||
|
||||
$translator->loadDomain('strings', $langPath);
|
||||
} else {
|
||||
/** @var $translator \Gettext\Translator */
|
||||
if (file_exists($langPath . '/' . $locale . '/LC_MESSAGES/strings.mo')) {
|
||||
$translator->loadTranslations(Gettext\Translations::fromMoFile($langPath . '/' . $locale . '/LC_MESSAGES/strings.mo'));
|
||||
} elseif (file_exists($langPath . '/' . $locale . '/LC_MESSAGES/strings.po')) {
|
||||
$translator->loadTranslations(Gettext\Translations::fromPoFile($langPath . '/' . $locale . '/LC_MESSAGES/strings.po'));
|
||||
}
|
||||
}
|
||||
});
|
||||
$middleware->setUriParamName('lang');
|
||||
|
||||
$app->add($middleware);
|
|
@ -9,9 +9,17 @@ use Slim\Http\Response;
|
|||
* @var $app \Slim\App
|
||||
*/
|
||||
|
||||
$app->get('/servers', \Friendica\Directory\Routes\Http\Servers::class);
|
||||
$app->get('/servers', \Friendica\Directory\Routes\Web\Servers::class);
|
||||
|
||||
$app->get('/search[/{account_type}]', \Friendica\Directory\Routes\Http\Search::class)->setName('search');
|
||||
$app->get('/search[/{account_type}]', function (Request $request, Response $response, $args) {
|
||||
if ($request->getAttribute('negotiation')->getMediaType() == 'application/json') {
|
||||
$route = new \Friendica\Directory\Routes\Http\Search($this);
|
||||
} else {
|
||||
$route = new \Friendica\Directory\Routes\Web\Search($this);
|
||||
}
|
||||
|
||||
return $route($request, $response, $args);
|
||||
})->setName('search');
|
||||
|
||||
$app->get('/submit', \Friendica\Directory\Routes\Http\Submit::class);
|
||||
|
||||
|
@ -26,4 +34,4 @@ $app->get('/VERSION', function (Request $request, Response $response) {
|
|||
return $response;
|
||||
});
|
||||
|
||||
$app->get('/[{account_type}]', \Friendica\Directory\Routes\Http\Directory::class)->setName('directory');
|
||||
$app->get('/[{account_type}]', \Friendica\Directory\Routes\Web\Directory::class)->setName('directory');
|
||||
|
|
|
@ -18,6 +18,11 @@ if (\is_readable(__DIR__ . '/../config/local.json')) {
|
|||
$settings = [
|
||||
'displayErrorDetails' => false, // set to false in production
|
||||
'addContentLengthHeader' => false, // Allow the web server to send the content-length header
|
||||
'i18n' => [
|
||||
'locales' => ['en', 'fr'],
|
||||
'default' => 'en',
|
||||
'path' => __DIR__ . '/lang'
|
||||
],
|
||||
// Escaper settings
|
||||
'escaper' => [
|
||||
'encoding' => 'utf-8'
|
||||
|
|
12
src/templates/widget/popularlanguages.phtml
Normal file
12
src/templates/widget/popularlanguages.phtml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<div>
|
||||
<h3><?php echo $this->__('Popular Languages')?></h3>
|
||||
<ul>
|
||||
<?php foreach ($languages as $language): ?>
|
||||
<li>
|
||||
<a href="search?field=language&q=<?php echo $this->escapeUrl($language['language']) ?>">
|
||||
<?php echo $this->e(Friendica\Directory\Utils\L10n::langToString($language['language'])) ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
Loading…
Reference in a new issue