summaryrefslogtreecommitdiff
path: root/modules/gallery/libraries/I18n.php
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gallery/libraries/I18n.php')
-rw-r--r--modules/gallery/libraries/I18n.php410
1 files changed, 410 insertions, 0 deletions
diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php
new file mode 100644
index 00000000..c936be88
--- /dev/null
+++ b/modules/gallery/libraries/I18n.php
@@ -0,0 +1,410 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2009 Bharat Mediratta
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * Translates a localizable message.
+ * @param $message String The message to be translated. E.g. "Hello world"
+ * @param $options array (optional) Options array for key value pairs which are used
+ * for pluralization and interpolation. Special key: "locale" to override the
+ * currently configured locale.
+ * @return String The translated message string.
+ */
+function t($message, $options=array()) {
+ return I18n::instance()->translate($message, $options);
+}
+
+/**
+ * Translates a localizable message with plural forms.
+ * @param $singular String The message to be translated. E.g. "There is one album."
+ * @param $plural String The plural message to be translated. E.g.
+ * "There are %count albums."
+ * @param $count Number The number which is inserted for the %count placeholder and
+ * which is used to select the proper plural form ($singular or $plural).
+ * @param $options array (optional) Options array for key value pairs which are used
+ * for pluralization and interpolation. Special key: "locale" to override the
+ * currently configured locale.
+ * @return String The translated message string.
+ */
+function t2($singular, $plural, $count, $options=array()) {
+ return I18n::instance()->translate(array("one" => $singular, "other" => $plural),
+ array_merge($options, array("count" => $count)));
+}
+
+class I18n_Core {
+ private static $_instance;
+ private $_config = array();
+ private $_call_log = array();
+ private $_cache = array();
+
+ private function __construct($config) {
+ $this->_config = $config;
+ $this->locale($config['default_locale']);
+ }
+
+ public static function instance($config=null) {
+ if (self::$_instance == NULL || isset($config)) {
+ $config = isset($config) ? $config : Kohana::config('locale');
+ if (empty($config['default_locale'])) {
+ $config['default_locale'] = module::get_var('core', 'default_locale');
+ }
+ self::$_instance = new I18n_Core($config);
+ }
+
+ return self::$_instance;
+ }
+
+ public function locale($locale=null) {
+ if ($locale) {
+ $this->_config['default_locale'] = $locale;
+ // Attempt to set PHP's locale as well (for number formatting, collation, etc.)
+ // TODO: See G2 for better fallack code.
+ $locale_prefs = array($locale);
+ $locale_prefs[] = 'en_US';
+ setlocale(LC_ALL, $locale_prefs);
+ }
+ return $this->_config['default_locale'];
+ }
+
+ /**
+ * Translates a localizable message.
+ * @param $message String|array The message to be translated. E.g. "Hello world"
+ * or array("one" => "One album", "other" => "%count albums")
+ * @param $options array (optional) Options array for key value pairs which are used
+ * for pluralization and interpolation. Special keys are "count" and "locale",
+ * the latter to override the currently configured locale.
+ * @return String The translated message string.
+ */
+ public function translate($message, $options=array()) {
+ $locale = empty($options['locale']) ? $this->_config['default_locale'] : $options['locale'];
+ $count = isset($options['count']) ? $options['count'] : null;
+ $values = $options;
+ unset($values['locale']);
+ $this->log($message, $options);
+
+ $entry = $this->lookup($locale, $message);
+
+ if (null === $entry) {
+ // Default to the root locale.
+ $entry = $message;
+ $locale = $this->_config['root_locale'];
+ }
+
+ $entry = $this->pluralize($locale, $entry, $count);
+
+ $entry = $this->interpolate($locale, $entry, $values);
+
+ return $entry;
+ }
+
+ private function lookup($locale, $message) {
+ if (!isset($this->_cache[$locale])) {
+ $this->_cache[$locale] = array();
+ // TODO: Load data from locale file instead of the DB.
+ foreach (Database::instance()
+ ->select("key", "translation")
+ ->from("incoming_translations")
+ ->where(array("locale" => $locale))
+ ->get()
+ ->as_array() as $row) {
+ $this->_cache[$locale][$row->key] = unserialize($row->translation);
+ }
+
+ // Override incoming with outgoing...
+ foreach (Database::instance()
+ ->select("key", "translation")
+ ->from("outgoing_translations")
+ ->where(array("locale" => $locale))
+ ->get()
+ ->as_array() as $row) {
+ $this->_cache[$locale][$row->key] = unserialize($row->translation);
+ }
+ }
+
+ $key = self::get_message_key($message);
+
+ if (isset($this->_cache[$locale][$key])) {
+ return $this->_cache[$locale][$key];
+ } else {
+ return null;
+ }
+ }
+
+ public function has_translation($message, $options=null) {
+ $locale = empty($options['locale']) ? $this->_config['default_locale'] : $options['locale'];
+ $count = empty($options['count']) ? null : $options['count'];
+ $values = $options;
+ unset($values['locale']);
+ $this->log($message, $options);
+
+ $entry = $this->lookup($locale, $message);
+
+ if (null === $entry) {
+ return false;
+ } else if (!is_array($entry)) {
+ return $entry !== '';
+ } else {
+ $plural_key = self::get_plural_key($locale, $count);
+ return isset($entry[$plural_key])
+ && $entry[$plural_key] !== null
+ && $entry[$plural_key] !== '';
+ }
+ }
+
+ public static function get_message_key($message) {
+ $as_string = is_array($message) ? implode('|', $message) : $message;
+ return md5($as_string);
+ }
+
+ private function interpolate($locale, $string, $values) {
+ // TODO: Handle locale specific number formatting.
+
+ // Replace x_y before replacing x.
+ krsort($values, SORT_STRING);
+
+ $keys = array();
+ foreach (array_keys($values) as $key) {
+ $keys[] = "%$key";
+ }
+ return str_replace($keys, array_values($values), $string);
+ }
+
+ private function pluralize($locale, $entry, $count) {
+ if (!is_array($entry)) {
+ return $entry;
+ }
+
+ $plural_key = self::get_plural_key($locale, $count);
+ if (!isset($entry[$plural_key])) {
+ // Fallback to the default plural form.
+ $plural_key = 'other';
+ }
+
+ if (isset($entry[$plural_key])) {
+ return $entry[$plural_key];
+ } else {
+ // Fallback to just any plural form.
+ list ($plural_key, $string) = each($entry);
+ return $string;
+ }
+ }
+
+ private function log($message, $options) {
+ $key = self::get_message_key($message);
+ isset($this->_call_log[$key]) or $this->_call_log[$key] = array($message, $options);
+ }
+
+ public function call_log() {
+ return $this->_call_log;
+ }
+
+ private static function get_plural_key($locale, $count) {
+ $parts = explode('_', $locale);
+ $language = $parts[0];
+
+ // Data from CLDR 1.6 (http://unicode.org/cldr/data/common/supplemental/plurals.xml).
+ // Docs: http://www.unicode.org/cldr/data/charts/supplemental/language_plural_rules.html
+ switch ($language) {
+ case 'az':
+ case 'fa':
+ case 'hu':
+ case 'ja':
+ case 'ko':
+ case 'my':
+ case 'to':
+ case 'tr':
+ case 'vi':
+ case 'yo':
+ case 'zh':
+ case 'bo':
+ case 'dz':
+ case 'id':
+ case 'jv':
+ case 'ka':
+ case 'km':
+ case 'kn':
+ case 'ms':
+ case 'th':
+ return 'other';
+
+ case 'ar':
+ if ($count == 0) {
+ return 'zero';
+ } else if ($count == 1) {
+ return 'one';
+ } else if ($count == 2) {
+ return 'two';
+ } else if (is_int($count) && ($i = $count % 100) >= 3 && $i <= 10) {
+ return 'few';
+ } else if (is_int($count) && ($i = $count % 100) >= 11 && $i <= 99) {
+ return 'many';
+ } else {
+ return 'other';
+ }
+
+ case 'pt':
+ case 'am':
+ case 'bh':
+ case 'fil':
+ case 'tl':
+ case 'guw':
+ case 'hi':
+ case 'ln':
+ case 'mg':
+ case 'nso':
+ case 'ti':
+ case 'wa':
+ if ($count == 0 || $count == 1) {
+ return 'one';
+ } else {
+ return 'other';
+ }
+
+ case 'fr':
+ if ($count >= 0 and $count < 2) {
+ return 'one';
+ } else {
+ return 'other';
+ }
+
+ case 'lv':
+ if ($count == 0) {
+ return 'zero';
+ } else if ($count % 10 == 1 && $count % 100 != 11) {
+ return 'one';
+ } else {
+ return 'other';
+ }
+
+ case 'ga':
+ case 'se':
+ case 'sma':
+ case 'smi':
+ case 'smj':
+ case 'smn':
+ case 'sms':
+ if ($count == 1) {
+ return 'one';
+ } else if ($count == 2) {
+ return 'two';
+ } else {
+ return 'other';
+ }
+
+ case 'ro':
+ case 'mo':
+ if ($count == 1) {
+ return 'one';
+ } else if (is_int($count) && $count == 0 && ($i = $count % 100) >= 1 && $i <= 19) {
+ return 'few';
+ } else {
+ return 'other';
+ }
+
+ case 'lt':
+ if (is_int($count) && $count % 10 == 1 && $count % 100 != 11) {
+ return 'one';
+ } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 9 && ($i = $count % 100) < 11 && $i > 19) {
+ return 'few';
+ } else {
+ return 'other';
+ }
+
+ case 'hr':
+ case 'ru':
+ case 'sr':
+ case 'uk':
+ case 'be':
+ case 'bs':
+ case 'sh':
+ if (is_int($count) && $count % 10 == 1 && $count % 100 != 11) {
+ return 'one';
+ } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 4 && ($i = $count % 100) < 12 && $i > 14) {
+ return 'few';
+ } else if (is_int($count) && ($count % 10 == 0 || (($i = $count % 10) >= 5 && $i <= 9) || (($i = $count % 100) >= 11 && $i <= 14))) {
+ return 'many';
+ } else {
+ return 'other';
+ }
+
+ case 'cs':
+ case 'sk':
+ if ($count == 1) {
+ return 'one';
+ } else if (is_int($count) && $count >= 2 && $count <= 4) {
+ return 'few';
+ } else {
+ return 'other';
+ }
+
+ case 'pl':
+ if ($count == 1) {
+ return 'one';
+ } else if (is_int($count) && ($i = $count % 10) >= 2 && $i <= 4 &&
+ ($i = $count % 100) < 12 && $i > 14 && ($i = $count % 100) < 22 && $i > 24) {
+ return 'few';
+ } else {
+ return 'other';
+ }
+
+ case 'sl':
+ if ($count % 100 == 1) {
+ return 'one';
+ } else if ($count % 100 == 2) {
+ return 'two';
+ } else if (is_int($count) && ($i = $count % 100) >= 3 && $i <= 4) {
+ return 'few';
+ } else {
+ return 'other';
+ }
+
+ case 'mt':
+ if ($count == 1) {
+ return 'one';
+ } else if ($count == 0 || is_int($count) && ($i = $count % 100) >= 2 && $i <= 10) {
+ return 'few';
+ } else if (is_int($count) && ($i = $count % 100) >= 11 && $i <= 19) {
+ return 'many';
+ } else {
+ return 'other';
+ }
+
+ case 'mk':
+ if ($count % 10 == 1) {
+ return 'one';
+ } else {
+ return 'other';
+ }
+
+ case 'cy':
+ if ($count == 1) {
+ return 'one';
+ } else if ($count == 2) {
+ return 'two';
+ } else if ($count == 8 || $count == 11) {
+ return 'many';
+ } else {
+ return 'other';
+ }
+
+ default: // en, de, etc.
+ return $count == 1 ? 'one' : 'other';
+ }
+ }
+} \ No newline at end of file