聚會時間公告: 因應COSCUP 2011, Kalug 8月份休會一次

十二月 17, 2011

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» PHP 多國語系製作 i18n library 筆記 (二)

php-logo

繼續上篇講到 PHP 多國語系製作 i18n library 筆記 (一),相信大家使用上沒有任何問題,
但是一定會有共同疑問,那就是可不可以做到根據偵測瀏覽器來決定預設載入語系,也就是說 load method 只需要帶入第一個參數即可。

$lang = new Language();
$lang->load("about");
echo $lang->line("index") . "\n";


我們可以透過 $_SERVER['HTTP_ACCEPT_LANGUAGE'] 來取得瀏覽器語系資料,底下先來看 $_SERVER['HTTP_ACCEPT_LANGUAGE'] 輸出什麼資訊,以英文版 FireFox 為例

en-us,en;q=0.5

我們只需要 en-us 字串,所以寫一個 _default_lang method 來處理

private function _default_lang()
{
    $browser_lang = !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? strtolower(strtok(strip_tags($_SERVER['HTTP_ACCEPT_LANGUAGE']), ',')) : '';
    return (!empty($browser_lang) and array_key_exists($browser_lang, $this->_language_list)) ? strtolower($browser_lang) : 'en-us';
}

拿到 en-us 字串後,該如何對應到 language/english 目錄呢,那就是需要一個陣列對照表

$this->language_list = array(
    'en-us' => 'english',
    'zh-tw' => 'zh-tw'
);

並且將 load method 部份改寫

public function load($langfile = '', $idiom = 'english')
{
    // 省略幾千行程式碼 ......

    if ($idiom == '')
    {
        $deft_lang = $this->language_list[$this->__default_lang()];
        $idiom = ($deft_lang == '') ? 'english' : $deft_lang;
    }

    // 省略幾千行程式碼 ......
}

寫到這裡,我相信讀者又會出現一個疑問,那就是該如何切換語系呢?大部份都是透過 $_GET['lang'] 變數修改,並且將定存放在 session,接著看如何寫這段程式碼

private function _set_language()
{
    $lang = (isset($_GET['lang'])) ? strtolower($_GET['lang']) : (isset($_GET['lang'])) ? strtolower($_GET['lang']) : "";
    if ($lang != '')
    {
        // check lang is exist in group
        if (array_key_exists($lang, $this->language_list))
        {
            $_SESSION['lang'] = $lang;
        }
    }

    // set default browser language
    if (!isset($_SESSION['lang']))
    {
        $_SESSION['lang'] = $this->_default_lang();
    }

    $this->language_folder = $this->language_list[$_SESSION['lang']];
    return $this;
}

load method 改成底下

public function load($langfile = '', $idiom = '')
{
    $this->_set_language();

    // 省略幾千行程式碼 ......

    if ($idiom == '')
    {
        $deft_lang = $this->language_folder;
        $idiom = ($deft_lang == '') ? 'english' : $deft_lang;
    }

    // 省略幾千行程式碼 ......

}

index.php 測試程式請改成

<?php
session_start();
include("Language.php");

$lang = new Language();

$lang->load("about");

echo "<h1>Index value</h1>";
echo "<p>" . $lang->line("index") . "</p>";
echo "<a href='index.php?lang=zh-TW'>Chinese</a> | <a href='index.php?lang=en-US'>English</a><br />";

上面程式碼已經完成一個簡單的多國語系雛型,這裏面會有一個小 bug,那就是假如兩個檔案 a.php 跟 b.php 語系檔裏面都包含

$lang['index'] = "xxxx";

這樣就會衝突,為了解決此問題,將架構改成

# load a 時
$this->load("a")
# load a 語系
$this->line("a.index")

# load a 時
$this->load("b")
# load a 語系
$this->line("b.index")

這時我們必須增加每個語系的 prefix

private function _set_prefix($lang = array())
{
    $output = array();
    foreach ($lang as $key => $val)
    {
        $key = $this->language_prefix . "." . $key;
        $output[$key] = $val;
    }

    return $output;
}

load method 改寫

public function load($langfile = '', $idiom = '')
{
    $this->_set_language();

    $langfile = str_replace('.php', '', $langfile);
    // set prefix name
    $this->language_prefix = $langfile;

    // 省略幾千行程式碼 ......

    // add prefix value of array key
    $lang = $this->_set_prefix($lang);
    $this->language = array_merge($this->language, $lang);
    unset($lang);

    return TRUE;
}

多國語系就介紹到這裡了,如可以到 php-i18n @ githib 參考程式碼,至於 CodeIgniter 可以參考 CodeIgniter-i18n @ github

Related View

十二月 16, 2011

小惡魔AppleBOY
AppleBOY
is about »

tag cloud

» PHP 多國語系製作 i18n library 筆記 (一)

php-logo

多國語系是目前網站必有的模組,至少都會支援繁體中文及英文,那大家都怎麼設計多國語系的架構呢,底下來一步一步來介紹。

多國語系目錄架構

language/
---> englisg/
---------> about.php
---> zh-tw/
---------> about.php
---> zh-cn/
---------> about.php

這是大部分的專案設計模式,也最容易清楚了解,接著我們就寫一個簡單的 Language Class 來動態讀取各國語系。

撰寫 Language Class

在根目錄新增 index.php 及 language.php,當然還有 language 多國語系目錄,檔案內容如下

index.php

<?php
include("Language.php");
$lang = new Language();

language.php

<?php
class Language {
    public function __construct()
    {
        echo "load language class\n";
    }
}

上面是 language 的初始化,直接下指令 php index.php 就會看到 load language class 畫面。接著必須規畫兩個 method,分別是載入 language 檔案,以及讀取資料,程式碼變成:

<?php

class Language {
    /**
     * List of translations
     *
     * @var array
     */

    var $language   = array();
    /**
     * List of loaded language files
     *
     * @var array
     */

    var $is_loaded  = array();

    public function __construct()
    {
        echo "load language class\n";
    }
    public function load($langfile = '', $idiom = 'english')
    {
        // 載入 language 檔案到 array()
    }

    public function line($line = '')
    {
        // 讀取 language list
    }
}

首先實作 load method,第一個參數帶入讀取的語系檔案,第二個參數帶入哪一種語系(例如: zh-tw 或 english),實作流程非常簡單,先將語系檔案載入後,所有語系都存入 $this->language 陣列,並且將檔名複製到 $this->is_loaded 陣列,代表已載入,避免重複。接著看看程式碼:

public function load($langfile = '', $idiom = 'english')
{
    $langfile = str_replace('.php', '', $langfile);

    $langfile .= '.php';

    if (in_array($langfile, $this->is_loaded, TRUE))
    {
        return;
    }

    if ($idiom == '')
    {
        $idiom = ($deft_lang == '') ? 'english' : $deft_lang;
    }

    // Determine where the language file is and load it
    if (file_exists('language/'.$idiom.'/'.$langfile))
    {
        include('language/'.$idiom.'/'.$langfile);
    }

    if ( ! isset($lang))
    {
        return;
    }

    $this->is_loaded[] = $langfile;
    $this->language = array_merge($this->language, $lang);
    unset($lang);

    return TRUE;
}

最後實作讀取語系

public function line($line = '')
{
    $value = ($line == '' OR ! isset($this->language[$line])) ? FALSE : $this->language[$line];

    return $value;
}

$this->language 不存在此變數,則回傳布林函數 FALSE。最後來測試看看,先針對兩個語系 english 跟 zh-tw 目錄底下新增 about.php,內容如下

<?php
$lang['index'] = "Home";

測試 php index.php

<?php

include("Language.php");

$lang = new Language();

$lang->load("about", "english");

echo $lang->line("index") . "\n";

這樣就完成了基本的多國語系 class 實作,當然還有很多應用,等下次有再繼續寫 XD。程式碼也同時放在 php-i18n @ github

>>>>> 繼續閱讀 PHP 多國語系製作 i18n library 筆記 (二) <<<<<

Related View

support:

biggo.com.tw

A Django site.