first commit
This commit is contained in:
121
plugins/system/languagefilter/languagefilter.xml
Normal file
121
plugins/system/languagefilter/languagefilter.xml
Normal file
@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<extension type="plugin" group="system" method="upgrade">
|
||||
<name>plg_system_languagefilter</name>
|
||||
<author>Joomla! Project</author>
|
||||
<creationDate>2010-07</creationDate>
|
||||
<copyright>(C) 2010 Open Source Matters, Inc.</copyright>
|
||||
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
|
||||
<authorEmail>admin@joomla.org</authorEmail>
|
||||
<authorUrl>www.joomla.org</authorUrl>
|
||||
<version>3.0.0</version>
|
||||
<description>PLG_SYSTEM_LANGUAGEFILTER_XML_DESCRIPTION</description>
|
||||
<namespace path="src">Joomla\Plugin\System\LanguageFilter</namespace>
|
||||
<files>
|
||||
<folder plugin="languagefilter">services</folder>
|
||||
<folder>src</folder>
|
||||
</files>
|
||||
<languages>
|
||||
<language tag="en-GB">language/en-GB/plg_system_languagefilter.ini</language>
|
||||
<language tag="en-GB">language/en-GB/plg_system_languagefilter.sys.ini</language>
|
||||
</languages>
|
||||
<config>
|
||||
<fields name="params">
|
||||
<fieldset name="basic">
|
||||
<field
|
||||
name="detect_browser"
|
||||
type="list"
|
||||
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_DETECT_BROWSER_LABEL"
|
||||
default="0"
|
||||
filter="integer"
|
||||
validate="options"
|
||||
>
|
||||
<option value="0">PLG_SYSTEM_LANGUAGEFILTER_SITE_LANGUAGE</option>
|
||||
<option value="1">PLG_SYSTEM_LANGUAGEFILTER_BROWSER_SETTINGS</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="automatic_change"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_AUTOMATIC_CHANGE_LABEL"
|
||||
default="1"
|
||||
filter="integer"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="item_associations"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ITEM_ASSOCIATIONS_LABEL"
|
||||
default="1"
|
||||
filter="integer"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="alternate_meta"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_ALTERNATE_META_LABEL"
|
||||
default="1"
|
||||
filter="integer"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="xdefault"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LABEL"
|
||||
default="1"
|
||||
filter="integer"
|
||||
showon="alternate_meta:1"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="xdefault_language"
|
||||
type="contentlanguage"
|
||||
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_XDEFAULT_LANGUAGE_LABEL"
|
||||
default="default"
|
||||
showon="alternate_meta:1[AND]xdefault:1"
|
||||
>
|
||||
<option value="default">PLG_SYSTEM_LANGUAGEFILTER_OPTION_DEFAULT_LANGUAGE</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="remove_default_prefix"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_REMOVE_DEFAULT_PREFIX_LABEL"
|
||||
default="0"
|
||||
filter="integer"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
|
||||
<field
|
||||
name="lang_cookie"
|
||||
type="list"
|
||||
label="PLG_SYSTEM_LANGUAGEFILTER_FIELD_COOKIE_LABEL"
|
||||
default="0"
|
||||
filter="integer"
|
||||
validate="options"
|
||||
>
|
||||
<option value="1">PLG_SYSTEM_LANGUAGEFILTER_OPTION_YEAR</option>
|
||||
<option value="0">PLG_SYSTEM_LANGUAGEFILTER_OPTION_SESSION</option>
|
||||
</field>
|
||||
</fieldset>
|
||||
</fields>
|
||||
</config>
|
||||
</extension>
|
||||
50
plugins/system/languagefilter/services/provider.php
Normal file
50
plugins/system/languagefilter/services/provider.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Plugin
|
||||
* @subpackage System.languagefilter
|
||||
*
|
||||
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
\defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Extension\PluginInterface;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\LanguageFactoryInterface;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Router\SiteRouter;
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
use Joomla\Plugin\System\LanguageFilter\Extension\LanguageFilter;
|
||||
|
||||
return new class () implements ServiceProviderInterface {
|
||||
/**
|
||||
* Registers the service provider with a DI container.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 4.4.0
|
||||
*/
|
||||
public function register(Container $container): void
|
||||
{
|
||||
$container->set(
|
||||
PluginInterface::class,
|
||||
function (Container $container) {
|
||||
$plugin = new LanguageFilter(
|
||||
$container->get(DispatcherInterface::class),
|
||||
(array) PluginHelper::getPlugin('system', 'languagefilter'),
|
||||
Factory::getApplication(),
|
||||
$container->get(LanguageFactoryInterface::class)
|
||||
);
|
||||
$plugin->setSiteRouter($container->get(SiteRouter::class));
|
||||
|
||||
return $plugin;
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
856
plugins/system/languagefilter/src/Extension/LanguageFilter.php
Normal file
856
plugins/system/languagefilter/src/Extension/LanguageFilter.php
Normal file
@ -0,0 +1,856 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Plugin
|
||||
* @subpackage System.languagefilter
|
||||
*
|
||||
* @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org>
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace Joomla\Plugin\System\LanguageFilter\Extension;
|
||||
|
||||
use Joomla\CMS\Application\ApplicationHelper;
|
||||
use Joomla\CMS\Application\CMSApplicationInterface;
|
||||
use Joomla\CMS\Association\AssociationServiceInterface;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\CMS\Language\Associations;
|
||||
use Joomla\CMS\Language\LanguageFactoryInterface;
|
||||
use Joomla\CMS\Language\LanguageHelper;
|
||||
use Joomla\CMS\Language\Multilanguage;
|
||||
use Joomla\CMS\Plugin\CMSPlugin;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Router\Router;
|
||||
use Joomla\CMS\Router\SiteRouterAwareTrait;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\Component\Menus\Administrator\Helper\MenusHelper;
|
||||
use Joomla\Event\DispatcherInterface;
|
||||
use Joomla\Filesystem\Path;
|
||||
use Joomla\Registry\Registry;
|
||||
use Joomla\String\StringHelper;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
\defined('_JEXEC') or die;
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
/**
|
||||
* Joomla! Language Filter Plugin.
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
final class LanguageFilter extends CMSPlugin
|
||||
{
|
||||
use SiteRouterAwareTrait;
|
||||
|
||||
/**
|
||||
* The routing mode.
|
||||
*
|
||||
* @var boolean
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $mode_sef;
|
||||
|
||||
/**
|
||||
* Available languages by sef.
|
||||
*
|
||||
* @var array
|
||||
* @since 1.6
|
||||
*/
|
||||
protected $sefs;
|
||||
|
||||
/**
|
||||
* Available languages by language codes.
|
||||
*
|
||||
* @var array
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $lang_codes;
|
||||
|
||||
/**
|
||||
* The current language code.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.4.2
|
||||
*/
|
||||
protected $current_lang;
|
||||
|
||||
/**
|
||||
* The default language code.
|
||||
*
|
||||
* @var string
|
||||
* @since 2.5
|
||||
*/
|
||||
protected $default_lang;
|
||||
|
||||
/**
|
||||
* The logged user language code.
|
||||
*
|
||||
* @var string
|
||||
* @since 3.3.1
|
||||
*/
|
||||
private $user_lang_code;
|
||||
|
||||
/**
|
||||
* The language factory
|
||||
*
|
||||
* @var LanguageFactoryInterface
|
||||
*
|
||||
* @since 4.4.0
|
||||
*/
|
||||
private $languageFactory;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param DispatcherInterface $dispatcher The dispatcher
|
||||
* @param array $config An optional associative array of configuration settings
|
||||
* @param CMSApplicationInterface $app The language factory
|
||||
* @param LanguageFactoryInterface $languageFactory The language factory
|
||||
*
|
||||
* @since 1.6.0
|
||||
*/
|
||||
public function __construct(
|
||||
DispatcherInterface $dispatcher,
|
||||
array $config,
|
||||
CMSApplicationInterface $app,
|
||||
LanguageFactoryInterface $languageFactory
|
||||
) {
|
||||
parent::__construct($dispatcher, $config);
|
||||
|
||||
$this->languageFactory = $languageFactory;
|
||||
|
||||
$this->setApplication($app);
|
||||
|
||||
// Setup language data.
|
||||
$this->mode_sef = $this->getApplication()->get('sef', 0);
|
||||
$this->sefs = LanguageHelper::getLanguages('sef');
|
||||
$this->lang_codes = LanguageHelper::getLanguages('lang_code');
|
||||
$this->default_lang = ComponentHelper::getParams('com_languages')->get('site', 'en-GB');
|
||||
|
||||
// If language filter plugin is executed in a site page.
|
||||
if ($this->getApplication()->isClient('site')) {
|
||||
$levels = $this->getApplication()->getIdentity()->getAuthorisedViewLevels();
|
||||
|
||||
foreach ($this->sefs as $sef => $language) {
|
||||
// @todo: In Joomla 2.5.4 and earlier access wasn't set. Non modified Content Languages got 0 as access value
|
||||
// we also check if frontend language exists and is enabled
|
||||
if (
|
||||
($language->access && !\in_array($language->access, $levels))
|
||||
|| (!\array_key_exists($language->lang_code, LanguageHelper::getInstalledLanguages(0)))
|
||||
) {
|
||||
unset($this->lang_codes[$language->lang_code], $this->sefs[$language->sef]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If language filter plugin is executed in an admin page (ex: Route site).
|
||||
// Set current language to default site language, fallback to en-GB if there is no content language for the default site language.
|
||||
$this->current_lang = isset($this->lang_codes[$this->default_lang]) ? $this->default_lang : 'en-GB';
|
||||
|
||||
foreach ($this->sefs as $sef => $language) {
|
||||
if (!\array_key_exists($language->lang_code, LanguageHelper::getInstalledLanguages(0))) {
|
||||
unset($this->lang_codes[$language->lang_code]);
|
||||
unset($this->sefs[$language->sef]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After initialise.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function onAfterInitialise()
|
||||
{
|
||||
$router = $this->getSiteRouter();
|
||||
|
||||
// Attach build rules for language SEF.
|
||||
$router->attachBuildRule([$this, 'preprocessBuildRule'], Router::PROCESS_BEFORE);
|
||||
|
||||
if ($this->mode_sef) {
|
||||
$router->attachBuildRule([$this, 'buildRule'], Router::PROCESS_BEFORE);
|
||||
$router->attachBuildRule([$this, 'postprocessSEFBuildRule'], Router::PROCESS_AFTER);
|
||||
} else {
|
||||
$router->attachBuildRule([$this, 'postprocessNonSEFBuildRule'], Router::PROCESS_AFTER);
|
||||
}
|
||||
|
||||
// Attach parse rule.
|
||||
$router->attachParseRule([$this, 'parseRule'], Router::PROCESS_BEFORE);
|
||||
}
|
||||
|
||||
/**
|
||||
* After route.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public function onAfterRoute()
|
||||
{
|
||||
// Add custom site name.
|
||||
if ($this->getApplication()->isClient('site') && isset($this->lang_codes[$this->current_lang]) && $this->lang_codes[$this->current_lang]->sitename) {
|
||||
$this->getApplication()->set('sitename', $this->lang_codes[$this->current_lang]->sitename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add build preprocess rule to router.
|
||||
*
|
||||
* @param Router &$router Router object.
|
||||
* @param Uri &$uri Uri object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public function preprocessBuildRule(&$router, &$uri)
|
||||
{
|
||||
$lang = $uri->getVar('lang', $this->current_lang);
|
||||
|
||||
if (isset($this->sefs[$lang])) {
|
||||
$lang = $this->sefs[$lang]->lang_code;
|
||||
}
|
||||
|
||||
$uri->setVar('lang', $lang);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add build rule to router.
|
||||
*
|
||||
* @param Router &$router Router object.
|
||||
* @param Uri &$uri Uri object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function buildRule(&$router, &$uri)
|
||||
{
|
||||
$lang = $uri->getVar('lang');
|
||||
|
||||
if (isset($this->lang_codes[$lang])) {
|
||||
$sef = $this->lang_codes[$lang]->sef;
|
||||
} else {
|
||||
$sef = $this->lang_codes[$this->current_lang]->sef;
|
||||
}
|
||||
|
||||
if (
|
||||
!$this->params->get('remove_default_prefix', 0)
|
||||
|| $lang !== $this->default_lang
|
||||
|| $lang !== $this->current_lang
|
||||
) {
|
||||
$uri->setPath($uri->getPath() . '/' . $sef . '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* postprocess build rule for SEF URLs
|
||||
*
|
||||
* @param Router &$router Router object.
|
||||
* @param Uri &$uri Uri object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public function postprocessSEFBuildRule(&$router, &$uri)
|
||||
{
|
||||
$uri->delVar('lang');
|
||||
}
|
||||
|
||||
/**
|
||||
* postprocess build rule for non-SEF URLs
|
||||
*
|
||||
* @param Router &$router Router object.
|
||||
* @param Uri &$uri Uri object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.4
|
||||
*/
|
||||
public function postprocessNonSEFBuildRule(&$router, &$uri)
|
||||
{
|
||||
$lang = $uri->getVar('lang');
|
||||
|
||||
if (isset($this->lang_codes[$lang])) {
|
||||
$uri->setVar('lang', $this->lang_codes[$lang]->sef);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add parse rule to router.
|
||||
*
|
||||
* @param Router &$router Router object.
|
||||
* @param Uri &$uri Uri object.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function parseRule(&$router, &$uri)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We are not in SEF mode
|
||||
$lang_code = $this->getLanguageCookie();
|
||||
|
||||
if (!$lang_code && $this->params->get('detect_browser', 1)) {
|
||||
$lang_code = LanguageHelper::detectLanguage();
|
||||
}
|
||||
|
||||
if (!isset($this->lang_codes[$lang_code])) {
|
||||
$lang_code = $this->default_lang;
|
||||
}
|
||||
}
|
||||
|
||||
$lang = $uri->getVar('lang', $lang_code);
|
||||
|
||||
if (isset($this->sefs[$lang])) {
|
||||
// We found our language
|
||||
$found = true;
|
||||
$lang_code = $this->sefs[$lang]->lang_code;
|
||||
}
|
||||
|
||||
// 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 (
|
||||
$this->getApplication()->getInput()->getMethod() === 'POST'
|
||||
|| $this->getApplication()->getInput()->get('nolangfilter', 0) == 1
|
||||
|| \count($this->getApplication()->getInput()->post) > 0
|
||||
|| \count($this->getApplication()->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();
|
||||
}
|
||||
|
||||
if (!isset($this->lang_codes[$lang_code])) {
|
||||
$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;
|
||||
|
||||
if ($this->params->get('detect_browser', 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->getApplication()->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();
|
||||
}
|
||||
|
||||
// Set redirect HTTP code to "302 Found".
|
||||
$redirectHttpCode = 302;
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Redirect to language.
|
||||
$this->getApplication()->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.
|
||||
$this->getApplication()->getInput()->set('language', $lang_code);
|
||||
$this->getApplication()->set('language', $lang_code);
|
||||
$language = $this->getApplication()->getLanguage();
|
||||
|
||||
if ($language->getTag() !== $lang_code) {
|
||||
$language_new = $this->languageFactory->createLanguage($lang_code, (bool) $this->getApplication()->get('debug_lang'));
|
||||
|
||||
foreach ($language->getPaths() as $extension => $files) {
|
||||
if (strpos($extension, 'plg_system') !== false) {
|
||||
$extension_name = substr($extension, 11);
|
||||
|
||||
$language_new->load($extension, JPATH_ADMINISTRATOR)
|
||||
|| $language_new->load($extension, JPATH_PLUGINS . '/system/' . $extension_name);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$language_new->load($extension);
|
||||
}
|
||||
|
||||
Factory::$language = $language_new;
|
||||
$this->getApplication()->loadLanguage($language_new);
|
||||
}
|
||||
|
||||
// Create a cookie.
|
||||
if ($this->getLanguageCookie() !== $lang_code) {
|
||||
$this->setLanguageCookie($lang_code);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the privacy related capabilities for this plugin to site administrators.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 3.9.0
|
||||
*/
|
||||
public function onPrivacyCollectAdminCapabilities()
|
||||
{
|
||||
$this->loadLanguage();
|
||||
|
||||
return [
|
||||
$this->getApplication()->getLanguage()->_('PLG_SYSTEM_LANGUAGEFILTER') => [
|
||||
$this->getApplication()->getLanguage()->_('PLG_SYSTEM_LANGUAGEFILTER_PRIVACY_CAPABILITY_LANGUAGE_COOKIE'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Before store user method.
|
||||
*
|
||||
* Method is called before user data is stored in the database.
|
||||
*
|
||||
* @param array $user Holds the old user data.
|
||||
* @param boolean $isnew True if a new user is stored.
|
||||
* @param array $new Holds the new user data.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function onUserBeforeSave($user, $isnew, $new)
|
||||
{
|
||||
if (\array_key_exists('params', $user) && $this->params->get('automatic_change', 1) == 1) {
|
||||
$registry = new Registry($user['params']);
|
||||
$this->user_lang_code = $registry->get('language');
|
||||
|
||||
if (empty($this->user_lang_code)) {
|
||||
$this->user_lang_code = $this->current_lang;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After store user method.
|
||||
*
|
||||
* Method is called after user data is stored in the database.
|
||||
*
|
||||
* @param array $user Holds the new user data.
|
||||
* @param boolean $isnew True if a new user is stored.
|
||||
* @param boolean $success True if user was successfully stored in the database.
|
||||
* @param string $msg Message.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public function onUserAfterSave($user, $isnew, $success, $msg): void
|
||||
{
|
||||
if ($success && \array_key_exists('params', $user) && $this->params->get('automatic_change', 1) == 1) {
|
||||
$registry = new Registry($user['params']);
|
||||
$lang_code = $registry->get('language');
|
||||
|
||||
if (empty($lang_code)) {
|
||||
$lang_code = $this->current_lang;
|
||||
}
|
||||
|
||||
if ($lang_code === $this->user_lang_code || !isset($this->lang_codes[$lang_code])) {
|
||||
if ($this->getApplication()->isClient('site')) {
|
||||
$this->getApplication()->setUserState('com_users.edit.profile.redirect', null);
|
||||
}
|
||||
} else {
|
||||
if ($this->getApplication()->isClient('site')) {
|
||||
$this->getApplication()->setUserState('com_users.edit.profile.redirect', 'index.php?Itemid='
|
||||
. $this->getApplication()->getMenu()->getDefault($lang_code)->id . '&lang=' . $this->lang_codes[$lang_code]->sef);
|
||||
|
||||
// Create a cookie.
|
||||
$this->setLanguageCookie($lang_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to handle any login logic and report back to the subject.
|
||||
*
|
||||
* @param array $user Holds the user data.
|
||||
* @param array $options Array holding options (remember, autoregister, group).
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public function onUserLogin($user, $options = [])
|
||||
{
|
||||
if ($this->getApplication()->isClient('site')) {
|
||||
$menu = $this->getApplication()->getMenu();
|
||||
|
||||
if ($this->params->get('automatic_change', 1)) {
|
||||
$assoc = Associations::isEnabled();
|
||||
$lang_code = $user['language'];
|
||||
|
||||
// If no language is specified for this user, we set it to the site default language
|
||||
if (empty($lang_code)) {
|
||||
$lang_code = $this->default_lang;
|
||||
}
|
||||
|
||||
// The language has been deleted/disabled or the related content language does not exist/has been unpublished
|
||||
// or the related home page does not exist/has been unpublished
|
||||
if (
|
||||
!\array_key_exists($lang_code, $this->lang_codes)
|
||||
|| !\array_key_exists($lang_code, Multilanguage::getSiteHomePages())
|
||||
|| !Folder::exists(JPATH_SITE . '/language/' . $lang_code)
|
||||
) {
|
||||
$lang_code = $this->current_lang;
|
||||
}
|
||||
|
||||
// Try to get association from the current active menu item
|
||||
$active = $menu->getActive();
|
||||
|
||||
$foundAssociation = false;
|
||||
|
||||
/**
|
||||
* Looking for associations.
|
||||
* If the login menu item form contains an internal URL redirection,
|
||||
* This will override the automatic change to the user preferred site language.
|
||||
* In that case we use the redirect as defined in the menu item.
|
||||
* Otherwise we redirect, when available, to the user preferred site language.
|
||||
*/
|
||||
if ($active && !$active->getParams()->get('login_redirect_url')) {
|
||||
if ($assoc) {
|
||||
$associations = MenusHelper::getAssociations($active->id);
|
||||
}
|
||||
|
||||
// Retrieves the Itemid from a login form.
|
||||
$uri = new Uri($this->getApplication()->getUserState('users.login.form.return'));
|
||||
|
||||
if ($uri->getVar('Itemid')) {
|
||||
// The login form contains a menu item redirection. Try to get associations from that menu item.
|
||||
// If any association set to the user preferred site language, redirect to that page.
|
||||
if ($assoc) {
|
||||
$associations = MenusHelper::getAssociations($uri->getVar('Itemid'));
|
||||
}
|
||||
|
||||
if (isset($associations[$lang_code]) && $menu->getItem($associations[$lang_code])) {
|
||||
$associationItemid = $associations[$lang_code];
|
||||
$this->getApplication()->setUserState('users.login.form.return', 'index.php?Itemid=' . $associationItemid);
|
||||
$foundAssociation = true;
|
||||
}
|
||||
} elseif (isset($associations[$lang_code]) && $menu->getItem($associations[$lang_code])) {
|
||||
/**
|
||||
* The login form does not contain a menu item redirection.
|
||||
* The active menu item has associations.
|
||||
* We redirect to the user preferred site language associated page.
|
||||
*/
|
||||
$associationItemid = $associations[$lang_code];
|
||||
$this->getApplication()->setUserState('users.login.form.return', 'index.php?Itemid=' . $associationItemid);
|
||||
$foundAssociation = true;
|
||||
} elseif ($active->home) {
|
||||
// We are on a Home page, we redirect to the user preferred site language Home page.
|
||||
$item = $menu->getDefault($lang_code);
|
||||
|
||||
if ($item && $item->language !== $active->language && $item->language !== '*') {
|
||||
$this->getApplication()->setUserState('users.login.form.return', 'index.php?Itemid=' . $item->id);
|
||||
$foundAssociation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($foundAssociation && $lang_code !== $this->current_lang) {
|
||||
// Change language.
|
||||
$this->current_lang = $lang_code;
|
||||
|
||||
// Create a cookie.
|
||||
$this->setLanguageCookie($lang_code);
|
||||
|
||||
// Change the language code.
|
||||
$this->languageFactory->createLanguage($lang_code);
|
||||
}
|
||||
} else {
|
||||
if ($this->getApplication()->getUserState('users.login.form.return')) {
|
||||
$this->getApplication()->setUserState('users.login.form.return', Route::_($this->getApplication()->getUserState('users.login.form.return'), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to add alternative meta tags for associated menu items.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public function onAfterDispatch()
|
||||
{
|
||||
$doc = $this->getApplication()->getDocument();
|
||||
|
||||
if ($this->getApplication()->isClient('site') && $this->params->get('alternate_meta', 1) && $doc->getType() === 'html') {
|
||||
$languages = $this->lang_codes;
|
||||
$homes = Multilanguage::getSiteHomePages();
|
||||
$menu = $this->getApplication()->getMenu();
|
||||
$active = $menu->getActive();
|
||||
$levels = $this->getApplication()->getIdentity()->getAuthorisedViewLevels();
|
||||
$remove_default_prefix = $this->params->get('remove_default_prefix', 0);
|
||||
$server = Uri::getInstance()->toString(['scheme', 'host', 'port']);
|
||||
$is_home = false;
|
||||
|
||||
// Router can be injected when turned into a DI built plugin
|
||||
$currentInternalUrl = 'index.php?' . http_build_query($this->getSiteRouter()->getVars());
|
||||
|
||||
if ($active) {
|
||||
$active_link = Route::_($active->link . '&Itemid=' . $active->id);
|
||||
$current_link = Route::_($currentInternalUrl);
|
||||
|
||||
// Load menu associations
|
||||
if ($active_link === $current_link) {
|
||||
$associations = MenusHelper::getAssociations($active->id);
|
||||
}
|
||||
|
||||
// Check if we are on the home page
|
||||
$is_home = ($active->home
|
||||
&& ($active_link === $current_link || $active_link === $current_link . 'index.php' || $active_link . '/' === $current_link));
|
||||
}
|
||||
|
||||
// Load component associations.
|
||||
$option = $this->getApplication()->getInput()->get('option');
|
||||
|
||||
$component = $this->getApplication()->bootComponent($option);
|
||||
|
||||
if ($component instanceof AssociationServiceInterface) {
|
||||
$cassociations = $component->getAssociationsExtension()->getAssociationsForItem();
|
||||
} else {
|
||||
$cName = ucfirst(substr($option, 4)) . 'HelperAssociation';
|
||||
\JLoader::register($cName, Path::clean(JPATH_SITE . '/components/' . $option . '/helpers/association.php'));
|
||||
|
||||
if (class_exists($cName) && \is_callable([$cName, 'getAssociations'])) {
|
||||
$cassociations = \call_user_func([$cName, 'getAssociations']);
|
||||
}
|
||||
}
|
||||
|
||||
// For each language...
|
||||
foreach ($languages as $i => $language) {
|
||||
switch (true) {
|
||||
// Language without frontend UI || Language without specific home menu || Language without authorized access level
|
||||
case !\array_key_exists($i, LanguageHelper::getInstalledLanguages(0)):
|
||||
case !isset($homes[$i]):
|
||||
case isset($language->access) && $language->access && !\in_array($language->access, $levels):
|
||||
unset($languages[$i]);
|
||||
break;
|
||||
|
||||
// Home page
|
||||
case $is_home:
|
||||
$language->link = Route::_('index.php?lang=' . $language->sef . '&Itemid=' . $homes[$i]->id);
|
||||
break;
|
||||
|
||||
// Current language link
|
||||
case $i === $this->current_lang:
|
||||
$language->link = Route::_($currentInternalUrl);
|
||||
break;
|
||||
|
||||
// Component association
|
||||
case isset($cassociations[$i]):
|
||||
$language->link = Route::_($cassociations[$i]);
|
||||
break;
|
||||
|
||||
// Menu items association
|
||||
// Heads up! "$item = $menu" here below is an assignment, *NOT* comparison
|
||||
case isset($associations[$i]) && ($item = $menu->getItem($associations[$i])):
|
||||
$language->link = Route::_('index.php?Itemid=' . $item->id . '&lang=' . $language->sef);
|
||||
break;
|
||||
|
||||
// Too bad...
|
||||
default:
|
||||
unset($languages[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
// If there are at least 2 of them, add the rel="alternate" links to the <head>
|
||||
if (\count($languages) > 1) {
|
||||
// Remove the sef from the default language if "Remove URL Language Code" is on
|
||||
if ($remove_default_prefix && isset($languages[$this->default_lang])) {
|
||||
$languages[$this->default_lang]->link
|
||||
= preg_replace('|/' . $languages[$this->default_lang]->sef . '/|', '/', $languages[$this->default_lang]->link, 1);
|
||||
}
|
||||
|
||||
foreach ($languages as $i => $language) {
|
||||
$doc->addHeadLink($server . $language->link, 'alternate', 'rel', ['hreflang' => $i]);
|
||||
}
|
||||
|
||||
// Add x-default language tag
|
||||
if ($this->params->get('xdefault', 1)) {
|
||||
$xdefault_language = $this->params->get('xdefault_language', $this->default_lang);
|
||||
$xdefault_language = ($xdefault_language === 'default') ? $this->default_lang : $xdefault_language;
|
||||
|
||||
if (isset($languages[$xdefault_language])) {
|
||||
// Use a custom tag because addHeadLink is limited to one URI per tag
|
||||
$doc->addCustomTag('<link href="' . $server . $languages[$xdefault_language]->link . '" rel="alternate" hreflang="x-default">');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the language cookie
|
||||
*
|
||||
* @param string $languageCode The language code for which we want to set the cookie
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @since 3.4.2
|
||||
*/
|
||||
private function setLanguageCookie($languageCode)
|
||||
{
|
||||
// If is set to use language cookie for a year in plugin params, save the user language in a new cookie.
|
||||
if ((int) $this->params->get('lang_cookie', 0) === 1) {
|
||||
// Create a cookie with one year lifetime.
|
||||
$this->getApplication()->getInput()->cookie->set(
|
||||
ApplicationHelper::getHash('language'),
|
||||
$languageCode,
|
||||
[
|
||||
'expires' => time() + 365 * 86400,
|
||||
'path' => $this->getApplication()->get('cookie_path', '/'),
|
||||
'domain' => $this->getApplication()->get('cookie_domain', ''),
|
||||
'secure' => $this->getApplication()->isHttpsForced(),
|
||||
'httponly' => true,
|
||||
]
|
||||
);
|
||||
} else {
|
||||
// If not, set the user language in the session (that is already saved in a cookie).
|
||||
$this->getApplication()->getSession()->set('plg_system_languagefilter.language', $languageCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the language cookie
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 3.4.2
|
||||
*/
|
||||
private function getLanguageCookie()
|
||||
{
|
||||
// Is is set to use a year language cookie in plugin params, get the user language from the cookie.
|
||||
if ((int) $this->params->get('lang_cookie', 0) === 1) {
|
||||
$languageCode = $this->getApplication()->getInput()->cookie->get(ApplicationHelper::getHash('language'));
|
||||
} else {
|
||||
// Else get the user language from the session.
|
||||
$languageCode = $this->getApplication()->getSession()->get('plg_system_languagefilter.language');
|
||||
}
|
||||
|
||||
// Let's be sure we got a valid language code. Fallback to null.
|
||||
if (!\array_key_exists($languageCode, $this->lang_codes)) {
|
||||
$languageCode = null;
|
||||
}
|
||||
|
||||
return $languageCode;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user