aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--composer.json3
-rw-r--r--composer.lock58
-rw-r--r--lib/classes/JsonApi/Middlewares/Language.php89
-rw-r--r--lib/classes/JsonApi/middleware.php3
4 files changed, 151 insertions, 2 deletions
diff --git a/composer.json b/composer.json
index 696383c..0310469 100644
--- a/composer.json
+++ b/composer.json
@@ -52,6 +52,7 @@
"symfony/console": "~5.3.16",
"symfony/process": "^5.4",
"jumbojett/openid-connect-php": "^0.9.2",
- "league/oauth2-server": "^8.3"
+ "league/oauth2-server": "^8.3",
+ "willdurand/negotiation": "^3.1"
}
}
diff --git a/composer.lock b/composer.lock
index 1acf6b6..29f2142 100644
--- a/composer.lock
+++ b/composer.lock
@@ -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": "c5b753821c3aa77c5de49e8932b47994",
+ "content-hash": "7a9043e1984ae4fb02e5872928486f0a",
"packages": [
{
"name": "algo26-matthias/idna-convert",
@@ -4019,6 +4019,62 @@
}
],
"time": "2021-09-14T12:46:25+00:00"
+ },
+ {
+ "name": "willdurand/negotiation",
+ "version": "3.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/willdurand/Negotiation.git",
+ "reference": "68e9ea0553ef6e2ee8db5c1d98829f111e623ec2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/68e9ea0553ef6e2ee8db5c1d98829f111e623ec2",
+ "reference": "68e9ea0553ef6e2ee8db5c1d98829f111e623ec2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1.0"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^5.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Negotiation\\": "src/Negotiation"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "William Durand",
+ "email": "will+git@drnd.me"
+ }
+ ],
+ "description": "Content Negotiation tools for PHP provided as a standalone library.",
+ "homepage": "http://williamdurand.fr/Negotiation/",
+ "keywords": [
+ "accept",
+ "content",
+ "format",
+ "header",
+ "negotiation"
+ ],
+ "support": {
+ "issues": "https://github.com/willdurand/Negotiation/issues",
+ "source": "https://github.com/willdurand/Negotiation/tree/3.1.0"
+ },
+ "time": "2022-01-30T20:08:53+00:00"
}
],
"packages-dev": [
diff --git a/lib/classes/JsonApi/Middlewares/Language.php b/lib/classes/JsonApi/Middlewares/Language.php
new file mode 100644
index 0000000..8843445
--- /dev/null
+++ b/lib/classes/JsonApi/Middlewares/Language.php
@@ -0,0 +1,89 @@
+<?php
+namespace JsonApi\Middlewares;
+
+use Negotiation\LanguageNegotiator;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
+
+/**
+ * This class defines a middleware that tries to set the language for Stud.IP
+ * by analyzing the HTTP header "Accept-Language".
+ *
+ * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
+ */
+class Language
+{
+ /**
+ * @param Request $request das Request-Objekt
+ * @param RequestHandler $handler der PSR-15 Request Handler
+ *
+ * @return ResponseInterface das neue Response-Objekt
+ */
+ public function __invoke(Request $request, RequestHandler $handler)
+ {
+ $language = $this->detectValidLanguageFromRequest($request);
+
+ // Set language if detected
+ if ($language) {
+ $_SESSION['_language'] = $language;
+ setTempLanguage(false, $language);
+ }
+
+ return $handler->handle($request);
+ }
+
+ /**
+ * Tries to detect a valid installed language from the request.
+ *
+ * @param Request $request
+ * @return string|null The detected language (if any)
+ */
+ private function detectValidLanguageFromRequest(Request $request): ?string
+ {
+ if (!$request->hasHeader('Accept-Language')) {
+ return null;
+ }
+
+ $negotiator = new LanguageNegotiator();
+ $best_language = $negotiator->getBest(
+ $request->getHeaderLine('Accept-Language'),
+ $this->getStudIPLanguagePriorities()
+ );
+
+ if (!$best_language) {
+ return null;
+ }
+
+ return $this->normalizeLanguageForStudIP($best_language->getType());
+ }
+
+ /**
+ * Returns a list of the normalized installed languages for the Stud.IP
+ * system.
+ *
+ * @return array
+ */
+ private function getStudIPLanguagePriorities(): array
+ {
+ return array_map(
+ function ($language) {
+ return str_replace('_', '-', $language);
+ },
+ array_keys($GLOBALS['INSTALLED_LANGUAGES'])
+ );
+ }
+
+ /**
+ * Normalizes the given language string (<language>-<variety>, e.g. de-de)
+ * for Stud.IP (e.g. de_DE).
+ *
+ * @param string $language
+ * @return string
+ */
+ private function normalizeLanguageForStudIP(string $language): string
+ {
+ $tags = explode('-', $language);
+ return $tags[0] . '_' . strtoupper($tags[1]);
+ }
+}
diff --git a/lib/classes/JsonApi/middleware.php b/lib/classes/JsonApi/middleware.php
index 7a318d5..f65231c 100644
--- a/lib/classes/JsonApi/middleware.php
+++ b/lib/classes/JsonApi/middleware.php
@@ -26,6 +26,9 @@ return function (App $app) {
// Add Routing Middleware
$app->addRoutingMiddleware();
+ // Add language middleware
+ $app->add(new Middlewares\Language());
+
/** @var array|null */
$corsOrigin = \Config::get()->getValue('JSONAPI_CORS_ORIGIN');
if (is_array($corsOrigin) && count($corsOrigin)) {