Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 96 additions & 140 deletions plugins/system/languagefilter/src/Extension/LanguageFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ public function onAfterInitialise(AfterInitialiseEvent $event): void

// Attach parse rule.
$router->attachParseRule([$this, 'parseRule'], Router::PROCESS_BEFORE);
$router->attachParseRule([$this, 'setLanguageApplicationState'], Router::PROCESS_BEFORE);
}

/**
Expand Down Expand Up @@ -304,7 +305,6 @@ public function buildRule(&$router, &$uri)
if (
!$this->params->get('remove_default_prefix', 0)
|| $lang !== $this->default_lang
|| $lang !== $this->current_lang
) {
$uri->setPath($uri->getPath() . '/' . $sef . '/');
}
Expand Down Expand Up @@ -356,179 +356,135 @@ public function postprocessNonSEFBuildRule(&$router, &$uri)
*/
public function parseRule(&$router, &$uri)
{
$app = $this->getApplication();

// Did we find the current and existing language yet?
$found = false;

// Are we in SEF mode or not?
if ($this->mode_sef) {
$path = $uri->getPath();
$parts = explode('/', $path);

$sef = StringHelper::strtolower($parts[0]);

// Do we have a URL Language Code ?
if (!isset($this->sefs[$sef])) {
// Check if remove default URL language code is set
if ($this->params->get('remove_default_prefix', 0)) {
if ($parts[0]) {
// We load a default site language page
$lang_code = $this->default_lang;
} else {
// We check for an existing language cookie
$lang_code = $this->getLanguageCookie();
}
} else {
$lang_code = $this->getLanguageCookie();
}

// No language code. Try using browser settings or default site language
if (!$lang_code && $this->params->get('detect_browser', 0) == 1) {
$lang_code = LanguageHelper::detectLanguage();
}

if (!$lang_code) {
$lang_code = $this->default_lang;
}

if ($lang_code === $this->default_lang && $this->params->get('remove_default_prefix', 0)) {
$found = true;
$sef = StringHelper::strtolower($parts[0]);
$lang = $uri->getVar('lang');

if (isset($this->sefs[$sef])) {
// We found a matching language to the lang code
$uri->setVar('lang', $this->sefs[$sef]->lang_code);
array_shift($parts);
$uri->setPath(implode('/', $parts));

// We were called with the default language code and want to redirect
if ($this->params->get('remove_default_prefix', 0) && $uri->getVar('lang') == $this->default_lang) {
$router->setTainted();
}
} elseif ($this->params->get('remove_default_prefix', 0)) {
// We don't have a prefix for the default language
$uri->setVar('lang', $this->default_lang);
} else {
// We found our language
$found = true;
$lang_code = $this->sefs[$sef]->lang_code;

// If we found our language, but it's the default language and we don't want a prefix for that, we are on a wrong URL.
// Or we try to change the language back to the default language. We need a redirect to the proper URL for the default language.
if ($lang_code === $this->default_lang && $this->params->get('remove_default_prefix', 0)) {
// Create a cookie.
$this->setLanguageCookie($lang_code);

$found = false;
array_shift($parts);
$path = implode('/', $parts);
}

// We have found our language and the first part of our URL is the language prefix
if ($found) {
array_shift($parts);

// Empty parts array when "index.php" is the only part left.
if (\count($parts) === 1 && $parts[0] === 'index.php') {
$parts = [];
}

$uri->setPath(implode('/', $parts));
}
// No language is set, so we want to redirect to the right language
$router->setTainted();
}
} else {
// We are not in SEF mode
$lang_code = $this->getLanguageCookie();

if (!$lang_code && $this->params->get('detect_browser', 1)) {
$lang_code = LanguageHelper::detectLanguage();
// The language was set both per SEF path and per query parameter. Query parameter takes precedence
if ($lang) {
$uri->setVar('lang', $lang);
$router->setTainted();
}
} elseif ($uri->hasVar('lang')) {
// We are not in SEF mode. Do we have a language set?
$lang_code = $uri->getVar('lang');

if (!isset($this->lang_codes[$lang_code])) {
$lang_code = $this->default_lang;
if (isset($this->sefs[$lang_code])) {
// We found a matching language to the lang code
$uri->setVar('lang', $this->sefs[$lang_code]->lang_code);
} else {
// The language is not installed on our site
$uri->delVar('lang');
}
}
}

$lang = $uri->getVar('lang', $lang_code);
/**
* Parse rule to set the applications language state.
* This rule is removed after being executed the first time, since
* it does redirects and thus disallows parsing more than one URL per page call
*
* @param Router &$router Router object.
* @param Uri &$uri Uri object.
*
* @return void
*
* @since __DEPLOY_VERSION__
*/
public function setLanguageApplicationState(&$router, &$uri)
{
// We check if the parseRule is still attached to keep this b/c
if (!\in_array([$this, 'parseRule'], $router->getRules()['parsepreprocess'])) {
$router->detachRule('parse', [$this, 'setLanguageApplicationState'], $router::PROCESS_BEFORE);

if (isset($this->sefs[$lang])) {
// We found our language
$found = true;
$lang_code = $this->sefs[$lang]->lang_code;
return;
}

// We are called via POST or the nolangfilter url parameter was set. We don't care about the language
// and simply set the default language as our current language.
if (
$app->getInput()->getMethod() === 'POST'
|| $app->getInput()->get('nolangfilter', 0) == 1
|| \count($app->getInput()->post) > 0
|| \count($app->getInput()->files) > 0
) {
$found = true;

if (!isset($lang_code)) {
$lang_code = $this->getLanguageCookie();
}

if (!$lang_code && $this->params->get('detect_browser', 1)) {
$lang_code = LanguageHelper::detectLanguage();
}
$lang_code = false;

if (!isset($this->lang_codes[$lang_code])) {
// Our parse rule discovered a language
if ($uri->hasVar('lang')) {
$lang_code = $uri->getVar('lang');
} else {
/**
* We don't know the language yet and want to discover it.
* If we remove the default prefix, call by POST or have nolangfilter set,
* we simply take the default language.
*/
if (
$this->params->get('remove_default_prefix', 0)
|| $this->getApplication()->getInput()->getMethod() === 'POST'
|| $this->getApplication()->getInput()->get('nolangfilter', 0) == 1
|| \count($this->getApplication()->getInput()->post) > 0
|| \count($this->getApplication()->getInput()->files) > 0
) {
$lang_code = $this->default_lang;
}
}

// We have not found the language and thus need to redirect
if (!$found) {
// Lets find the default language for this user
if (!isset($lang_code) || !isset($this->lang_codes[$lang_code])) {
$lang_code = false;
} else {
$lang_code = $this->getLanguageCookie();

if ($this->params->get('detect_browser', 1)) {
// No language code. Try using browser settings or default site language
if (!$lang_code && $this->params->get('detect_browser', 0) == 1) {
$lang_code = LanguageHelper::detectLanguage();

if (!isset($this->lang_codes[$lang_code])) {
$lang_code = false;
}
}

if (!$lang_code) {
$lang_code = $this->default_lang;
}
}

if ($this->mode_sef) {
// Use the current language sef or the default one.
if (
$lang_code !== $this->default_lang
|| !$this->params->get('remove_default_prefix', 0)
) {
$path = $this->lang_codes[$lang_code]->sef . '/' . $path;
}

$uri->setPath($path);
if (!$this->params->get('remove_default_prefix', 0) && $uri->getPath() == '') {
if ($this->mode_sef) {
$path = $this->lang_codes[$lang_code]->sef . '/' . $uri->getPath();

if (!$app->get('sef_rewrite')) {
$uri->setPath('index.php/' . $uri->getPath());
}

$redirectUri = $uri->base() . $uri->toString(['path', 'query', 'fragment']);
} else {
$uri->setVar('lang', $this->lang_codes[$lang_code]->sef);
$redirectUri = $uri->base() . 'index.php?' . $uri->getQuery();
}
if (!$this->getApplication()->get('sef_rewrite')) {
$path = 'index.php/' . $path;
}

// Set redirect HTTP code to "302 Found".
$redirectHttpCode = 302;
$uri->setPath($path);
} else {
$uri->setPath('index.php');
$uri->setVar('lang', $this->lang_codes[$lang_code]->sef);
}
$redirectHttpCode = 301;
$redirectUri = $uri->base() . $uri->toString(['path', 'query', 'fragment']);

// If selected language is the default language redirect code is "301 Moved Permanently".
if ($lang_code === $this->default_lang) {
$redirectHttpCode = 301;
// We cannot cache this redirect in browser. 301 is cacheable by default so we need to force to not cache it in browsers.
$this->getApplication()->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true);
$this->getApplication()->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true);
$this->getApplication()->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate', false);
$this->getApplication()->sendHeaders();

// We cannot cache this redirect in browser. 301 is cacheable by default so we need to force to not cache it in browsers.
$app->setHeader('Expires', 'Wed, 17 Aug 2005 00:00:00 GMT', true);
$app->setHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT', true);
$app->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate', false);
$app->sendHeaders();
// Redirect to language.
$this->getApplication()->redirect($redirectUri, $redirectHttpCode);
}
}

// Redirect to language.
$app->redirect($redirectUri, $redirectHttpCode);
}

// We have found our language and now need to set the cookie and the language value in our system
$this->current_lang = $lang_code;

// Set the request var.
$app = $this->getApplication();
$app->getInput()->set('language', $lang_code);
$app->set('language', $lang_code);
$language = $app->getLanguage();
Expand All @@ -554,9 +510,9 @@ public function parseRule(&$router, &$uri)
}

// Create a cookie.
if ($this->getLanguageCookie() !== $lang_code) {
$this->setLanguageCookie($lang_code);
}
$this->setLanguageCookie($lang_code);

$router->detachRule('parse', [$this, 'setLanguageApplicationState'], $router::PROCESS_BEFORE);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions plugins/system/sef/src/Extension/Sef.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Joomla\CMS\Event\Application\AfterInitialiseEvent;
use Joomla\CMS\Event\Application\AfterRenderEvent;
use Joomla\CMS\Event\Application\AfterRouteEvent;
use Joomla\CMS\Language\LanguageHelper;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Router\Router;
Expand Down Expand Up @@ -339,6 +340,15 @@ public function enforceSuffix()
return;
}

// We don't force a suffix for the language homepage
$segments = explode('/', $route);
$last = array_pop($segments);
$sefs = LanguageHelper::getLanguages('sef');

if ($this->getApplication()->getLanguageFilter() && isset($sefs[$last])) {
return;
}

$suffix = pathinfo($route, PATHINFO_EXTENSION);
$nonSEFSuffix = $origUri->getVar('format');

Expand Down
Loading