Browse Source

Add localization support using gettext extension

- new french translation files
- initialize locale and gettext in Core\Context constructor
- new Core\Context::t() function for translations and arguments.
Frederic G. MARAND 12 years ago
parent
commit
02e677133e

+ 67 - 2
Memcache_UI/Core/Context.inc

@@ -17,6 +17,13 @@ namespace Memcache_UI\Core {
      */
     protected $gc = NULL;
 
+    /**
+     * Locale with encoding
+     *
+     * This is a static because a page runs for only one locale.
+     */
+    protected static $locale = 'en_US.UTF8';
+
     /**
      * Logging level, as per RFC5424
      *
@@ -55,7 +62,8 @@ namespace Memcache_UI\Core {
     protected $user = FALSE;
 
     function __construct() {
-      $this->getTidy(); // Needed to check extension
+      $this->initLocale(); // Check extension and initialize locale
+      $this->getTidy(); // Needed to check optional extension
     }
 
     function __destruct() {
@@ -176,7 +184,7 @@ namespace Memcache_UI\Core {
           }
         }
         if (!$notified && $this->tidy && !extension_loaded('tidy')) {
-          $this->setMessage(strtr('Extension @tidy requested but missing: skipping', array(
+          $this->setMessage(t('Extension @tidy requested but missing: output formatting unavailable.', array(
             '@tidy' => 'tidy',
           )), LOG_WARNING);
           $notified = TRUE;
@@ -187,6 +195,51 @@ namespace Memcache_UI\Core {
       return $this->tidy;
     }
 
+    /**
+     * Initialize the locale based on the user Accept-Language header.
+     *
+     * @TODO support "xx" form, and not just "xx_YY".
+     * @TODO support more platforms. UNIX and MacOS X do not handle locales like Linux
+     *
+     * @link @link http://www.php.net/manual/fr/function.bind-textdomain-codeset.php#42631
+     *
+     * @return void
+     */
+    protected function initLocale() {
+      static $notified = FALSE;
+      if (!$notified && !extension_loaded('intl')) {
+        // Do not invoke t() before initializing locale
+        $this->setMessage(strtr('Extension @intl requested but missing: translations unavailable.', array(
+          '@intl' => 'intl',
+        )), LOG_WARNING);
+      }
+
+      $locale = \Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
+      $this->setMessage(strtr('Requested locale: @locale', array('@locale' => $locale)), LOG_DEBUG);
+      if (!empty($locale)) {
+        $matches = array();
+        $count = preg_match('/^([a-z]{2}_[A-Z]{2})(\.(\w+))*/', $locale, $matches);
+        if ($count) {
+          $count = count($matches);
+        }
+        $locale = $count >= 2
+          ? $matches[1]
+          : 'en_US';
+        $codeset = $count >= 4
+          ? $matches[3]
+          : 'UTF8';
+        self::$locale = $locale . '.' . $codeset;
+        setlocale(LC_ALL, self::$locale);
+
+        $domain = 'messages';
+        $translation_path = 'locale';
+        bindtextdomain($domain, $translation_path);
+        textdomain($domain);
+        bind_textdomain_codeset($domain, 'UTF8');
+        $this->setMessage(self::t('Locale: @locale', array('@locale' => self::$locale)), LOG_DEBUG);
+      }
+    }
+
     /**
      * Add a message to the messages list if it is above the current logging level.
      *
@@ -205,5 +258,17 @@ namespace Memcache_UI\Core {
         }
       }
     }
+
+    /**
+     * Wrapper to combine gettext translation and parameter substitution.
+     *
+     * @param string $message
+     * @param array $args
+     *
+     * @return string
+     */
+    static function t($message, $args = array()) {
+      return strtr(gettext($message), $args);
+    }
   }
 }

+ 2 - 1
Memcache_UI/Page/Main.inc

@@ -2,11 +2,12 @@
 namespace Memcache_UI\Page {
 
   use Memcache_UI\Core\Element;
+  use Memcache_UI\Core\Context;
 
   class Main extends Base {
     public function build() {
       parent::build();
-      $this->setBody(new Element('p', NULL, 'Hello world'));
+      $this->setBody(new Element('p', NULL, Context::t("Hello world\n")));
     }
   }
 }

BIN
locale/fr_FR/LC_MESSAGES/messages.mo


+ 36 - 0
locale/fr_FR/LC_MESSAGES/messages.po

@@ -0,0 +1,36 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Memcache UI\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-10-01 22:38+0100\n"
+"PO-Revision-Date: 2011-10-01 22:39+0100\n"
+"Last-Translator: Frederic G. MARAND <fgm@osinet.fr>\n"
+"Language-Team: OSInet <support@osinet.fr>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-KeywordsList: _;gettext;gettext_noop;t\n"
+"X-Poedit-Basepath: /home/marand/Dropbox/src/tools/memcache_ui\n"
+"Plural-Forms: Plural-Forms: nplurals=2; plural=n>1;\n"
+"X-Poedit-Language: French\n"
+"X-Poedit-Country: FRANCE\n"
+"X-Poedit-SourceCharset: utf-8\n"
+"X-Poedit-SearchPath-0: .\n"
+
+#: get.php:14
+msgid "Hello world\n"
+msgstr "Bonjour le monde\n"
+
+#: get.php:15
+msgid "Tomorrow\n"
+msgstr "Demain\n"
+
+#: Memcache_UI/Core/Context.inc:185
+msgid "Extension @tidy requested but missing: output formatting unavailable."
+msgstr "L'extension @tidy est nécessaire mais absente: le formatage en sortie n'est pas disponible."
+
+#: Memcache_UI/Core/Context.inc:206
+msgid "Extension @intl requested but missing: translations unavailable."
+msgstr "L'extension @intl est nécessaire mais absente: les traductions ne sont pas disponibles."
+

+ 14 - 0
memcache_ui.php

@@ -1,4 +1,18 @@
 <?php
+/**
+ * Memcache User Interface. Main file.
+ *
+ * @author Frederic G. MARAND <fgm@osinet.fr>
+ *
+ * @copyright (c) 2011 Frederic G. MARAND
+ *
+ * Requirements:
+ * - PHP >= 5.3
+ * - intl extension
+ *
+ * Recommended:
+ * - tidy extension
+ */
 namespace Memcache_UI {
 
   /**