-
-
Save sebastian-marinescu/4b2991bc40dbbc405257ba5846adb1ef to your computer and use it in GitHub Desktop.
<?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; |
Hi, yeah this looks about right. It should redirect to Russian site, if the browser has "ru" inside "HTTP_ACCEPT_LANGUAGE".
If not, then it should fall-back to your "web" context.
I have had some sort of erros with "too many redirects". Don't understand why...
There are 2 contexts, "web" and "ru". One of them is http://site.com/, another - http://site.com/ru. May be, context without "en" in address is not correct for this snippet?
Maybe it doesn't work without any language-code in it, you might be right.
But reverse-thought: can't you rename the contexts to "web-en" and "web-ru"?
Maybe it doesn't work without any language-code in it, you might be right.
But reverse-thought: can't you rename the contexts to "web-en" and "web-ru"?
There is the problem :) MODx doesn't let you change key of contexts, that already exists. I don't know, how to change "web" context key :(
Ahhhh, I remember :)
But I also remember, that you can change the key in the database.
Can you login to phpMyAdmin and change it there?
(if for some reason you can't, another idea I have is: duplicate the contexts with all it's contents and give it a new key)
Ahhhh, I remember :)
But I also remember, that you can change the key in the database.
Can you login to phpMyAdmin and change it there?(if for some reason you can't, another idea I have is: duplicate the contexts with all it's contents and give it a new key)
No resoursces after renaming)) Not good variant. It's doesn't work.
Copying context seems to be hard, bacause I have to chain every resource in babel :(
May be there is a variant to add some sort of parameter, where I can match "web" context to "en" cultureKey? Every next context will have the Key similar to it's cultureKey, but "web" is the problem...
In that case, you will have to adapt the script for your needs.
You could simplify the script drastically and just check manually if user/browser wants Russian, then send to "ru", if not, send to "web"; done.
Oh, hard work, I am not a developer)) Will try, thank you a lot.
Ahhhh, I remember :)
But I also remember, that you can change the key in the database.
Can you login to phpMyAdmin and change it there?(if for some reason you can't, another idea I have is: duplicate the contexts with all it's contents and give it a new key)
Is it right, that the snippet doesn't allow you to change language by babellinks? It will switch context every time, as I understand
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)
Hi, yeah this looks about right. It should redirect to Russian site, if the browser has "ru" inside "HTTP_ACCEPT_LANGUAGE".
If not, then it should fall-back to your "web" context.