This repository has been archived by the owner on Jun 4, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathAutodetectLanguage.module
181 lines (154 loc) · 7.88 KB
/
AutodetectLanguage.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
<?php
/**
* Autodetect Language
*
* This module tries to find a best match between a user's language
* and one of the installed site languages.
*
* Sets two session variables:
* $session->languageAlreadyDetected (true|false)
* $session->languageDetectionFailed (returns true if fell back to default);
*/
class AutodetectLanguage extends WireData implements Module, ConfigurableModule {
/**
* Return information about this module (required)
*
* @return array
*/
public static function getModuleInfo() {
return array(
'title' => "Autodetect Language",
'summary' => "Finds a best match between visitor's language and redirects.",
'author' => 'Pierre-Luc Auclair',
'version' => 103,
'singular' => true,
'autoload' => true,
);
}
public function init() {
wire()->addHookBefore("Page::render", $this, "detectLanguageRedirect");
}
public function __construct() {
$this->defaultSiteLanguageCode = "";
$this->onlyOnHomepage = "";
$this->noDetectGetParam = "";
}
public function detectLanguageRedirect(HookEvent $event) {
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$page = wire("page");
// defaults to "en" if unset
if (empty($this->defaultSiteLanguageCode)) {
$this->defaultSiteLanguageCode = "en";
}
$run = false;
if ($this->session->languageAlreadyDetected === null) {
if ($this->onlyOnHomepage == false) {
$run = true;
} elseif ($this->onlyOnHomepage == true AND $page->id == 1) {
$run = true;
} else {
$run = false;
$this->session->languageAlreadyDetected = true;
}
}
if ($run === true) {
// Initalize this session variable. Lets you know when
// the language detection failed and fell back to "default"
$this->session->languageDetectionFailed = true;
$acceptLanguages = explode(";", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
function cleanAcceptLanguages($string)
{
$string = $string;
$pattern = '/^(q=[0-9\.]+\,?)([\D\d]*)$/i';
// get rid of any q=x.x, we only want the language names
$replacement = '$2';
return strtolower(preg_replace($pattern, $replacement, $string));
}
// strip q=x.x
$acceptLanguages = array_map("cleanAcceptLanguages", $acceptLanguages);
// remove empty strings
$acceptLanguages = array_filter($acceptLanguages);
// split any string that looks like "en,en-us" in two
foreach ($acceptLanguages as $key => $value) {
$pattern = "/^(.+),(.+)$/";
if (preg_match($pattern, $value)) {
$acceptLanguages[$key] = preg_replace($pattern, "$1", $value);
array_splice($acceptLanguages, $key + 1, 0, preg_replace($pattern, "$2", $value));
}
}
// make lowercase array from site languages
$siteLanguages = array();
foreach (wire("languages") as $language) {
$languageName = strtolower($language->name);
array_push($siteLanguages, $languageName);
}
// remove first item, should always be "default",
// don't wanna match against that
$defaultLanguage = array_shift($siteLanguages);
// add default language code to list
array_push($siteLanguages, strtolower($this->defaultSiteLanguageCode));
// then track where to put it, if we need to fallback to default
$defaultLanguagePosition = sizeof($siteLanguages) - 1;
// keep track of match, if any
$matchedLanguage = "";
// first try full match (fr-fr)
foreach ($acceptLanguages as $accept) {
if (array_search($accept, $siteLanguages) !== false) {
$matchedLanguage = $accept;
$languageDetectionFailed = false;
break; // at first match
}
}
// if this didn't work, try partial match (fr)
if (empty($matchedLanguage)) {
$substr = function ($element) {
return substr($element, 0, 2);
};
$acceptLanguages = array_map($substr, $acceptLanguages);
$siteLanguagesShort = array_map($substr, $siteLanguages);
foreach ($acceptLanguages as $accept) {
if (array_search($accept, $siteLanguagesShort) !== false) {
$matchedLanguage = $accept;
$languageDetectionFailed = false;
break; // at first match
}
}
}
// if no match between HTTP_ACCEPT_LANGUAGE and site languages
if (empty($matchedLanguage)) {
$matchedLanguage = $defaultLanguage;
} elseif (array_search($matchedLanguage, $siteLanguages) == $defaultLanguagePosition) {
$matchedLanguage = $defaultLanguage;
}
// Set some session variables then redirect
$this->session->languageAlreadyDetected = true;
if (wire('user')->language->name != $matchedLanguage AND !isset(wire('input')->get->{$this->noDetectGetParam})) {
$this->session->redirect($page->localUrl($matchedLanguage), false);
}
}
}
}
public static function getModuleConfigInputfields(array $data) {
$inputfields = new InputfieldWrapper();
// Option to set the default language code
$field = wire('modules')->get('InputfieldText');
$field->name = 'defaultSiteLanguageCode';
$field->label = __("Default system language code");
$field->description = __("This setting informs the module what the language code is for the \"default\" system language. You should use a [BCP 47 formatted](http://www.rfc-editor.org/rfc/bcp/bcp47.txt) language code. These are the typical **us** or **en-US** you commonly see. Important note: all your language name fields in Setup > Languages must also conform to this format. **If not set, will default back to \"en\"**.");
if(isset($data['defaultSiteLanguageCode'])) $field->value = $data['defaultSiteLanguageCode'];
$inputfields->add($field);
$field = wire('modules')->get('InputfieldCheckbox');
$field->name ='onlyOnHomepage';
$field->label = 'Only detect language on homepage';
$field->attr('value', $data['onlyOnHomepage'] ? $data['onlyOnHomepage'] : 0 );
$field->attr('checked', $data['onlyOnHomepage'] === 1 ? 'checked' : '' );
$inputfields->add($field);
$field = wire('modules')->get('InputfieldText');
$field->name = 'noDetectGetParam';
$field->label = __("Do not detect language if GET parameter is set");
$field->description = __("If this GET parameter is set, AutodetectLanguage will not try to detect the user's language. This might be helpful for newsletters or other things. For example, if you were to set this setting to \"nodetect\" and the page would be accessed via *http://example.com/?nodetect*, redirection to the preferred user's language will not happen.");
if(isset($data['noDetectGetParam'])) $field->value = $data['noDetectGetParam'];
$inputfields->add($field);
return $inputfields;
}
}