-
-
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; |
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)

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...