Last active
April 23, 2021 12:09
-
-
Save sebastian-marinescu/4b2991bc40dbbc405257ba5846adb1ef to your computer and use it in GitHub Desktop.
A PHP snippet for MODX to redirect to accepted client-languages (adapted so it trims prefix/suffix before matching)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* LanguageMatch | |
* | |
* Based on https://gist.github.com/christianseel/504302ce8ddfcde009c0 | |
* Original code by http://stackoverflow.com/a/3771447 | |
* | |
* Updated by Indigo74 & x-vance for prefix/suffix and default context | |
*/ | |
$snippetName = 'LanguageMatch'; | |
// Verify required parameters | |
if (!isset($scriptProperties['ctxDefault'])) { | |
$modx->log(modX::LOG_LEVEL_ERROR, '['.$snippetName.'] is missing required property &ctxDefault!'); | |
return; | |
} | |
// Store parameters | |
define('CONTEXT_PREFIX', $modx->getOption('ctxPrefix', $scriptProperties, '')); | |
define('CONTEXT_SUFFIX', $modx->getOption('ctxSuffix', $scriptProperties, '')); | |
define('DEFAULT_CONTEXT', $modx->getOption('ctxDefault', $scriptProperties, 'web')); | |
// parse list of comma separated language tags and sort it by the quality value | |
function parseLanguageList($languageList) { | |
if (is_null($languageList)) { | |
if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { | |
return array(); | |
} | |
$languageList = $_SERVER['HTTP_ACCEPT_LANGUAGE']; | |
} | |
$languages = array(); | |
$languageRanges = explode(',', trim($languageList)); | |
foreach ($languageRanges as $languageRange) { | |
if (preg_match('/(\*|[a-zA-Z0-9]{1,8}(?:-[a-zA-Z0-9]{1,8})*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?/', trim($languageRange), $match)) { | |
if (!isset($match[2])) { | |
$match[2] = '1.0'; | |
} else { | |
$match[2] = (string) floatval($match[2]); | |
} | |
if (!isset($languages[$match[2]])) { | |
$languages[$match[2]] = array(); | |
} | |
$languages[$match[2]][] = strtolower($match[1]); | |
} | |
} | |
krsort($languages); | |
return $languages; | |
} | |
// compare two parsed arrays of language tags and find the matches | |
function findMatches($accepted, $available) { | |
$matches = array(); | |
$any = false; | |
foreach ($accepted as $acceptedQuality => $acceptedValues) { | |
$acceptedQuality = floatval($acceptedQuality); | |
if ($acceptedQuality === 0.0) continue; | |
foreach ($available as $availableQuality => $availableValues) { | |
$availableQuality = floatval($availableQuality); | |
if ($availableQuality === 0.0) continue; | |
foreach ($acceptedValues as $acceptedValue) { | |
if ($acceptedValue === '*') { | |
$any = true; | |
} | |
foreach ($availableValues as $availableValue) { | |
$matchingGrade = matchLanguage($acceptedValue, $availableValue); | |
if ($matchingGrade > 0) { | |
$q = (string) ($acceptedQuality * $availableQuality * $matchingGrade); | |
if (!isset($matches[$q])) { | |
$matches[$q] = array(); | |
} | |
if (!in_array($availableValue, $matches[$q])) { | |
$matches[$q][] = $availableValue; | |
} | |
} | |
} | |
} | |
} | |
} | |
if (count($matches) === 0 && $any) { | |
$matches = $available; | |
} | |
krsort($matches); | |
return $matches; | |
} | |
// compare two language tags and distinguish the degree of matching | |
function matchLanguage($a, $b) { | |
$a = explode('-', $a); | |
$b = explode('-', $b); | |
for ($i=0, $n=min(count($a), count($b)); $i<$n; $i++) { | |
if ($a[$i] !== $b[$i]) break; | |
} | |
return $i === 0 ? 0 : (float) $i / count($a); | |
} | |
//echo '<pre>'; | |
$accepted = parseLanguageList($_SERVER['HTTP_ACCEPT_LANGUAGE']); | |
//print_r($accepted); | |
$babelKeys = $modx->getOption('babel.contextKeys',null,'en'); | |
$patternCtx = '/' . CONTEXT_PREFIX . '(\w+)' . CONTEXT_SUFFIX . '/i'; | |
$languageKeys = preg_replace($patternCtx, '$1', $babelKeys); | |
$available = parseLanguageList($languageKeys); | |
//print_r($available); | |
$matches = findMatches($accepted, $available); | |
print_r($matches); | |
if (!empty($matches)) { | |
$matched_lang = array_shift(array_values($matches)); | |
$matched_lang = $matched_lang[0]; | |
} else { | |
$matched_lang = 'en'; | |
} | |
$context = $modx->getContext(CONTEXT_PREFIX . $matched_lang . CONTEXT_SUFFIX); | |
if (!$context) { | |
$context = $modx->getContext(DEFAULT_CONTEXT); | |
if (!$context) return 'CONTEXT NOT FOUND. (ERROR IN LANGUAGEMATCH SNIPPET)'; | |
} | |
$site_start = $context->getOption('site_start',null,$modx->getOption('site_start',null,1)); | |
$url = $modx->makeUrl($site_start); | |
$modx->sendRedirect($url, array('responseCode' => 'HTTP/1.1 302 Found')); | |
return; |
It was intended to be used like this originally:
I have copied web context to "en" and now I have three of them, web (/), en (/en/) and ru (/ru/). This code on the mainpage of "Web":
[[!LanguageMatch?
&ctxDefault=`en`
&ctxPrefix=``
]]
Ru is opening good, but my english Firefox send this:
Array ( [0.5] => Array ( [0] => en ) ) CONTEXT NOT FOUND. (ERROR IN LANGUAGEMATCH SNIPPET)
Help me pls, I don't understand, why there is impossible to find "en" context. (babel.contextKeys is "en,ru", default_context is "en").
Error log
[2021-04-23 14:21:42] (ERROR @ /home/k/komatera/polustrade.com/public_html/core/model/modx/modx.class.php : 1031) `0` is not a valid integer and may not be passed to makeUrl()
[2021-04-23 14:21:42] (ERROR in resource 3 @ /home/k/komatera/polustrade.com/public_html/core/model/modx/modparser.class.php : 1373) Bad link tag `[[~0]]` encountered
I uncommented "print" commands and that, what I have got:
Array
(
[1.0] => Array
(
[0] => en-us
)
[0.5] => Array
(
[0] => en
)
)
Array
(
[1.0] => Array
(
[0] => en
[1] => ru
)
)
Array
(
[0.5] => Array
(
[0] => en
)
)
CONTEXT NOT FOUND. (ERROR IN LANGUAGEMATCH SNIPPET)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It was intended to be used like this originally: