summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/gallery/helpers/locales.php85
-rw-r--r--modules/user/helpers/user.php18
-rw-r--r--modules/user/helpers/user_event.php24
-rw-r--r--modules/user/helpers/user_theme.php24
4 files changed, 145 insertions, 6 deletions
diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php
index 3762b97b..1320c155 100644
--- a/modules/gallery/helpers/locales.php
+++ b/modules/gallery/helpers/locales.php
@@ -23,6 +23,7 @@
*/
class locales_Core {
private static $locales;
+ private static $language_subtag_to_locale;
/**
* Return the list of available locales.
@@ -105,6 +106,16 @@ class locales_Core {
$l["zh_TW"] = "繁體中文"; // Chinese (TW)
asort($l, SORT_LOCALE_STRING);
self::$locales = $l;
+
+ // Language subtag to (default) locale mapping
+ foreach ($l as $locale => $name) {
+ list ($language) = explode("_", $locale . "_");
+ // The first one mentioned is the default
+ if (!isset($d[$language])) {
+ $d[$language] = $locale;
+ }
+ }
+ self::$language_subtag_to_locale = $d;
}
static function display_name($locale=null) {
@@ -121,4 +132,78 @@ class locales_Core {
list ($language, $territory) = explode('_', $locale . "_");
return in_array($language, array("he", "fa", "ar"));
}
+
+ /**
+ * Returns the best match comparing the HTTP accept-language header
+ * with the installed locales.
+ */
+ static function locale_from_http_request() {
+ $http_accept_language = Input::instance()->server("HTTP_ACCEPT_LANGUAGE");
+ if ($http_accept_language) {
+ // Parse the HTTP header and build a preference list
+ // Example value: "de,en-us;q=0.7,en-uk,fr-fr;q=0.2"
+ $locale_preferences = array();
+ foreach (explode(",", $http_accept_language) as $code) {
+ list ($requested_locale, $qvalue) = explode(";", $code . ";");
+ $requested_locale = trim($requested_locale);
+ $qvalue = trim($qvalue);
+ if (preg_match("/^([a-z]{2,3})(?:[_-]([a-zA-Z]{2}))?/", $requested_locale, $matches)) {
+ $requested_locale = strtolower($matches[1]);
+ if (!empty($matches[2])) {
+ $requested_locale .= "_" . strtoupper($matches[2]);
+ }
+ $requested_locale = trim(str_replace("-", "_", $requested_locale));
+ if (!strlen($qvalue)) {
+ // If not specified, default to 1.
+ $qvalue = 1;
+ } else {
+ // qvalue is expected to be something like "q=0.7"
+ list ($ignored, $qvalue) = explode("=", $qvalue . "==");
+ $qvalue = floatval($qvalue);
+ }
+ $locale_preferences[] = array($requested_locale, $qvalue);
+ }
+ }
+
+ // Compare and score requested locales with installed ones
+ $matched_locales = array();
+ foreach ($locale_preferences as $requested_value) {
+ $scored_locale_match = self::_locale_match_score($requested_value);
+ if ($scored_locale_match) {
+ $scored_locales[] = $scored_locale_match;
+ }
+ }
+
+ usort($matched_locales, array("locales", "_compare_locale_by_qvalue"));
+
+ $best_match = array_shift($scored_locales);
+ if ($best_match) {
+ return $best_match[0];
+ }
+ }
+
+ return null;
+ }
+
+ static function _compare_locale_by_qvalue($a, $b) {
+ $a = $a[1];
+ $b = $b[1];
+ if ($a == $b) {
+ return 0;
+ }
+ return $a < $b ? 1 : -1;
+ }
+
+ private static function _locale_match_score($requested_locale_and_qvalue) {
+ list ($requested_locale, $qvalue) = $requested_locale_and_qvalue;
+ $installed = self::installed();
+ if (isset($installed[$requested_locale])) {
+ return $requested_locale_and_qvalue;
+ }
+ list ($language) = explode("_", $requested_locale . "_");
+ if (isset(self::$language_subtag_to_locale[$language])) {
+ return array(self::$language_subtag_to_locale[$language], $qvalue * 0.66);
+ }
+ return null;
+ }
} \ No newline at end of file
diff --git a/modules/user/helpers/user.php b/modules/user/helpers/user.php
index 40acc2ec..b9162b92 100644
--- a/modules/user/helpers/user.php
+++ b/modules/user/helpers/user.php
@@ -87,6 +87,9 @@ class user_Core {
private static function _add_locale_dropdown(&$form, $user=null) {
$locales = locales::installed();
+ foreach ($locales as $locale => $display_name) {
+ $locales[$locale] = SafeString::of_safe_html($display_name);
+ }
if (count($locales) > 1) {
// Put "none" at the first position in the array
$locales = array_merge(array("" => t("« none »")), $locales);
@@ -336,4 +339,19 @@ class user_Core {
}
return $salt . md5($salt . $password);
}
+
+ static function cookie_locale() {
+ $cookie_data = Input::instance()->cookie("g_locale");
+ $locale = null;
+ if ($cookie_data) {
+ if (preg_match("/^([a-z]{2,3}(?:_[A-Z]{2})?)$/", trim($cookie_data), $matches)) {
+ $requested_locale = $matches[1];
+ $installed_locales = locales::installed();
+ if (isset($installed_locales[$requested_locale])) {
+ $locale = $requested_locale;
+ }
+ }
+ }
+ return $locale;
+ }
} \ No newline at end of file
diff --git a/modules/user/helpers/user_event.php b/modules/user/helpers/user_event.php
index 4bde224b..ede4e515 100644
--- a/modules/user/helpers/user_event.php
+++ b/modules/user/helpers/user_event.php
@@ -23,12 +23,7 @@ class user_event_Core {
*/
static function gallery_ready() {
user::load_user();
-
- $locale = user::active()->locale;
- if (!empty($locale)) {
- // TODO(andy_st): Check session data as well.
- I18n::instance()->locale($locale);
- }
+ self::set_request_locale();
}
static function admin_menu($menu, $theme) {
@@ -38,4 +33,21 @@ class user_event_Core {
->label(t("Users/Groups"))
->url(url::site("admin/users")));
}
+
+ static function set_request_locale() {
+ // 1. Check the session specific preference (cookie)
+ $locale = user::cookie_locale();
+ // 2. Check the user's preference
+ if (!$locale) {
+ $locale = user::active()->locale;
+ }
+ // 3. Check the browser's / OS' preference
+ if (!$locale) {
+ $locale = locales::locale_from_http_request();
+ }
+ // If we have any preference, override the site's default locale
+ if ($locale) {
+ I18n::instance()->locale($locale);
+ }
+ }
}
diff --git a/modules/user/helpers/user_theme.php b/modules/user/helpers/user_theme.php
index 8de2d248..5b973ef3 100644
--- a/modules/user/helpers/user_theme.php
+++ b/modules/user/helpers/user_theme.php
@@ -18,6 +18,14 @@
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class user_theme_Core {
+ static function head($theme) {
+ if (count(locales::installed())) {
+ // Needed by the languages block
+ $theme->script("jquery.cookie.js");
+ }
+ return "";
+ }
+
static function header_top($theme) {
if ($theme->page_type != "login") {
$view = new View("login.html");
@@ -25,4 +33,20 @@ class user_theme_Core {
return $view->render();
}
}
+
+ static function sidebar_blocks($theme) {
+ $locales = locales::installed();
+ foreach ($locales as $locale => $display_name) {
+ $locales[$locale] = SafeString::of_safe_html($display_name);
+ }
+ if (count($locales) > 1) {
+ $block = new Block();
+ $block->css_id = "gUserLanguageBlock";
+ $block->title = t("Select Language Preference");
+ $block->content = new View("user_languages_block.html");
+ $block->content->installed_locales = array_merge(array("" => t("« none »")), $locales);
+ $block->content->selected = (string) user::cookie_locale();
+ return $block;
+ }
+ }
}