如何將 PHP 應用程序國際化

對應用程序的本地化或者可以事先進行規劃,或者也可以過後追悔莫及。本文帶您探索有助於改進本地化過程或進行本地化規劃的技術和工具,如gettext、XML、XSLT 及設計模式等。

評估應用程序

本地化的要求非常模糊,如同說 “使應用程序準備好在德國使用” 一樣。但是即使當要求看似很詳細的時候,您還是可以發現產品經理沒考慮到的事情。

例如,就拿清單 1 中所示的標準的 Yahoo! RSS 新聞閱讀器應用程序來說。當頁面第一次被調用時,將顯示默認的標題列表,並且有一個表單字段,您可以在其中鍵入選擇的新聞類別,然後再重新提交頁面。該應用程序將驗證鍵入的類別,如果類別無效的話將顯示錯誤消息,或者顯示所請求類別的標題。


清單 1. 來自 Yahoo 的 RSS 新聞!

                
<?php

require_once "XML/RSS.php";

# Normalize and validate user input

$newstype = strtolower(isset(
對應用程序的本地化或者可以事先進行規劃,或者也可以過後追悔莫及。本文帶您探索有助於改進本地化過程或進行本地化規劃的技術和工具,如gettext、XML、XSLT 及設計模式等。

評估應用程序

本地化的要求非常模糊,如同說 “使應用程序準備好在德國使用” 一樣。但是即使當要求看似很詳細的時候,您還是可以發現產品經理沒考慮到的事情。

例如,就拿清單 1 中所示的標準的 Yahoo! RSS 新聞閱讀器應用程序來說。當頁面第一次被調用時,將顯示默認的標題列表,並且有一個表單字段,您可以在其中鍵入選擇的新聞類別,然後再重新提交頁面。該應用程序將驗證鍵入的類別,如果類別無效的話將顯示錯誤消息,或者顯示所請求類別的標題。


清單 1. 來自 Yahoo 的 RSS 新聞!

___FCKpd___0

雖然此應用程序很簡單,但是它說明了在本地化過程中出現的很多問題。它還反映了任何腳本語言的一些優缺點。

您總是可以按成本價迅速推出產品。 用戶界面 (UI)、業務邏輯和配置,或缺少其中一些元素,將它們混合在一起,而不考慮維護或擴展具有新功能的頁面。

在對此頁面進行德語本地化以及可能的其他語言本地化時,會遇到幾個障礙:

  • 應當重構代碼以分離各個應用層。
  • 必須提取並翻譯 UI 文本,例如標題、內容和錯誤消息。
  • 必須將諸如 Submit 按鈕之類的表單控件本地化。
  • 應用程序需要一種定義目標語言環境的方法。
  • 用戶輸入要求及驗證會因語言環境的不同而有所變化。
  • 考慮依賴於語言環境的業務規則,例如 Yahoo! RSS 提要的 URL;目標和語法會因國家或地區的不同而有所不同。
  • 對在各種語言環境中支持配置和控制應用程序域行爲的框架的需要更加迫切。

完成所有這些工作所需的投入很容易與原始應用程序的成本持平,或超出原始應用程序的成本 —— 全面考慮需要面對很多困難。因此,您的團隊必須對這些障礙有所準備,無論是在應用程序完成之前還是完成之後。





回頁首


本地化術語

如果您要在項目中與翻譯人員協作,那麼最好確保您瞭解一些可能在與翻譯人員的談話中會遇到的術語。表 1 定義了語言學家和專業翻譯人員使用的一些常用術語。


表 1. 本地化術語

術語 含義
語言環境 語言與國家或地區的組合 —— 例如 en_US、en_GB、de_DE
國際化 (I18N) 規劃、設計和準備要本地化的應用程序
本地化 (L10N) 識別並翻譯 (T9N) 用於目標語言環境的應用程序 UI
外在化(字符串提取) 提取程序字符串以供翻譯的過程




回頁首


花樣翻新的本地化

清單 2 顯示了經過重構翻新以支持本地化後的 RSS 應用程序。功能邏輯和本地化框架被抽象到處理程序類中。主代碼中需要完成的工作是構造頁面處理程序對象、HTML 模板並調用處理程序的 accessor 方法來填充 HTML 模板的動態部分。


清單 2. 經過本地化的 RSS 新聞

                
<?php
# news2.php
require_once "RSSHandler.php";
$handler = new RSSHandler;
?>

<html>
  <head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
    <title><?php echo $handler->getTitle() ?></title>
  </head>
  <body>
    <h1><?php echo $handler->getTitle() ?></h1>
    <p>
      <?php echo $handler->getGreeting() ?>
    </p>
    <?php $handler->showerror() ?>
    <form method = "POST">
      <input type = "text" name = "newstype" 
        value = "<?php echo $handler->getNewstype() ?>" />
      <br/>
      <input type = "submit" 
        value="<?php echo $handler->getSubmitbutton() ?>" />
    </form>
    <?php $handler->showHeadlines() ?>
  </body>
</html>

重構的優點是程序員可以更輕鬆地維護代碼。也就是說,UI 現在是否更具有可維護性是有疑義的,因爲它缺少語言環境,並且 HTML 的絕大部分仍嵌入在 PHP 代碼中。

PHP 程序員是否會信任 Web 開發人員所做的這些類型的更改?讓後端開發人員處理小的 UI 更改請求需要花費多少成本?稍後,我將展示擴展樣式表語言轉換(Extensible Stylesheet Language Transformation,XSLT)如何更好地分離應用層。

構造函數

讓我們從處理程序類的構造函數開始(參見 清單 3)來看看如何爲本地化翻新頁面。當頁面處理程序被實例化後,構造函數將確定相應的語言環境,檢索該語言環境的配置設置,驗證任何用戶輸入,根據用戶當前的語言環境計算所有以前的靜態內容,然後驗證任何用戶輸入。(要獲得源代碼,請參閱 下載。)


清單 3. RSSHandler.php

                
  public function __construct() {

    # set up locale
    putenv("LANG=de_DE");       # for the configuration
    setlocale(LC_ALL, 'de_DE');   # for gettext

    # Get locale-dependent configuration
    $this->conf = new RSSConfig;
    $this->configdecorator = new Configdecorator($this->conf);

    # set up the text extraction context
    bindtextdomain($this->conf->getTextdomainmessage(),  
      $this->conf->getTextdomainpath());
    textdomain($this->conf->getTextdomainmessage());
    
    # Extract the strings for translation.
    $errormsg = gettext("News type is not valid.");
    $this->title = gettext("Yahoo RSS News");
    $this->submitbutton = gettext("Get the news.");
    $lgreeting = 
      gettext("Welcome to the Yahoo RSS news reader. ") . " " .
      gettext("Enter a news type, then submit the form.") . " " .
      gettext ("Valid news types are: %s.");
    $decoratedtypes = $this->configdecorator->getNewsTypes();
    $this->greeting = sprintf($lgreeting, $decoratedtypes);
    
    # Normalize and validate 
    $this->newstype = $this->normalize();
    $this->error = $this->validate() ? '' : $errormsg;
  }

在本例中,爲了簡單起見,語言環境被硬編碼爲 de_DE。在現實情況中,您會需要根據業務要求設置語言環境。確定正確的語言環境有兩種常用方法:檢查請求 URL(例如,www.ebay.de、amazon.fr)或簡單地詢問用戶並在其瀏覽器中設置首選 cookie。

檢索配置參數

確定了語言環境後,處理程序將檢索德國配置參數。在本例中,配置包括使用 PEAR 軟件包 (Config.php)、XML 配置文件 (RSSConfig.xml)、特定於應用程序域的包裝器 (RSSConfig.php) 和一個簡單的裝飾類來爲一些配置參數添加 HTML 標記 (Configdecorator.php)。

清單 4 中所示的配置文件將以 XML 形式存儲其信息。它用於指定字符串提取的上下文(//conf/textdomain)—— 依賴於語言環境的組件的位置及消息文件的名稱。

注:如果下載並嘗試運行樣例,請確保更改路徑使其指向提取並翻譯後的字符串以匹配您的環境。

配置文件還將告訴應用程序如何構造正確的 Yahoo! 新聞提要 URL (//conf/de_DE/baseurl)、如何驗證用戶對新聞提要類型做出的選擇 (//conf/de_DE/newtypes) 以及在用戶沒有做出選擇的情況下哪類新聞應當爲默認值。


清單 4. Configuration.xml

                
<?xml version="1.0" encoding="UTF-8"?>
<conf>
    <textdomain>
    	<path>/home/bbradley/Sites</path>
	<messagefile>messages</messagefile>
    </textdomain>
    <en_US>
        <baseurl>http://rss.news.yahoo.com/rss/</baseurl>
        <newstypes>
            <type>
                <default>true</default>
                <name>tech</name>
                <url>tech</url>
                </type>
            <type>
                <default/>
                <name>world</name>
                <url>world</url>
                </type>
        </newstypes>
    </en_US>
    <de_DE>
        <baseurl>http://de.news.yahoo.com/</baseurl>
        <newstypes>
            <type>
                <default>true</default>
                <name>Ausland</name>
                <url>politik/ausland.html.xml</url>
                </type>
            <type>
                <name>Technik</name>
                <url>technik/index.html.xml</url>
                </type>
        </newstypes>
    </de_DE>
</conf>

您可以通過添加 “默認” 語言環境使配置更加健壯。然後,如果應用程序嘗試顯示無效的語言環境,則要始終保證一些合理的應用程序行爲。您還可以擴展配置以容納其他應用程序形式,例如品牌聯合或基於用戶權限的應用程序限制。

餘下的大多數處理程序對象包括衍生頁面中與每種語言環境相對應的文本部分,並且提供公共的 accessor 方法,這些方法使這些經過翻譯的文本可用於 HTML 模板。

gettext 提取框架

應用程序將使用一個名爲 gettext 的開源字符串提取框架以實例化經過翻譯的字符串。此框架有幾個優點:

  • 它是免費的。
  • 它可以在各種平臺上運行。
  • 它可以使用許多編程語言,包括 PHP。
  • 它特別適用於翻新工作。

要使用 gettext,請執行以下步驟:

  1. 爲必須支持的所有語言環境創建目錄結構。
  2. 通過將字符串移入特定函數 gettext() 的參數來標記字符串。
  3. 運行 xgettext 命令行實用程序將字符串提取到消息文件中。
  4. 將得到的消息文件複製到每個語言環境的專用目錄下。
  5. 編輯本地版本的消息文件並翻譯文本。
  6. 運行 msgfmt 命令行實用程序以創建在運行時使用的本地化的消息數據庫。

使用 gettext() 函數的目的很明顯 —— 在運行時檢索本地化的文本,認識到這一點很重要。但同等重要的是事實上它還是用於文本提取的 標記xgettext 實用程序將查找此函數標記的字符串。

清單 5 中顯示了樣例應用程序的所有軟件組件,包括在應用程序配置中定義的目錄結構。每個 gettext 實現都要求使用與此類似的目錄結構。無需爲默認語言環境創建目錄樹或消息數據庫;用於該語言環境的字符串已經被嵌入到代碼中。但是需要編輯 RSSConfig.xml 文件以正確標識指向 gettext 框架中這些文件的完整路徑。


清單 5. 目錄結構

                
ConfigDecorator.php -- Decorator class
de_DE -- Directory for Germany
	LC_MESSAGES -- Messages sub-directory
		messages.mo -- Compiled messages database
		messages.po -- Translated messages
messages.po -- Generated by xgettext
news2.php -- Main application / HTML template
RSSConfig.php -- Application configuration class
RSSConfig.xml -- Application configuration file
RSSHandler.php -- HTTP request handler / business logic

翻譯消息文件

在德語消息文件中,翻譯人員必須提供的部分被標記爲粗體。換言之,翻譯人員必須填空。當翻譯人員首次打開消息文件時,這些部分將爲空,並且翻譯人員必須指定要使用的字符編碼(在本例中爲 Latin-1)和翻譯。消息 ID (msgid) 是用於提取而調用 gettext() 函數進行標記的原始文本。消息字符串 (msgstr) 是必須用目標語言顯示的字符串。清單 6 顯示了當用戶指定了錯誤的消息類型時錯誤消息的翻譯。


清單 6. 德語消息文件 messages.po.de

                
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION/n"
"Report-Msgid-Bugs-To: /n"
"POT-Creation-Date: 2006-11-05 11:05-0800/n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE/n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>/n"
"Language-Team: LANGUAGE <[email protected]>/n"
"MIME-Version: 1.0/n"
"Content-Type: text/plain; charset=ISO-8859-1/n"
"Content-Transfer-Encoding: 8bit/n"

#: RSSHandler.php:31
msgid "News type is not valid."
msgstr "Die Nachrichtkategorie ist falsch."

如果任何已提取的字符串的文本在任何時候發生更改,則在每次生成消息文件時將創建新消息 ID。每次添加或更改字符串時,都應當重新生成消息文件,否則將在目標語言環境顯示未翻譯的新文本。

在生產環境中,L10N 團隊通常會執行所有這些任務(除了準備源代碼以外)。但是這不意味着您可以完全不受語言問題的影響。將應用程序本地化時需要切記以下要點:

  • 不要將功能信息嵌入到字符串中。
  • 在完整的句子中使用 printf 標記來標記動態內容而不要將句子分割爲多個字符串。記住不同語言之間的句子中的語序是不同的;您可以讓翻譯人員來控制語序。如果字符串包含多個動態元素,則 msgfmt 支持擴展標記語法,該語法允許您指定字符串中每個動態元素的位置。在翻譯過程中可以輕鬆地更改元素的順序。您可以在任意一本 gettext 的聯機手冊中瞭解關於位置語法的更多信息(請參閱 參考資料)。
  • 確保字符串具有足夠的有意義的上下文。記住翻譯人員將只能看到字符串 —— 而不是運行的應用程序。

注:有關將軟件本地化時在語言方面的更多建議,請參閱 參考資料

當添加新文本或重述現有文本時,本地化團隊可以使用其他 gettext 實用程序將新字符串或更改的字符串合併到現有消息文件中,從而免去重新翻譯的需求。





回頁首


設計本地化

在大多數情況下按照上述方法處理本地化很可能足夠優秀。但是,隨着範圍的擴大,考慮使用設計模式來設計應用程序會十分有意義。最廣泛使用的一種模式是 Model-View-Controller (MVC)。此模式鼓勵您分層(表示層、域層、數據訪問層)處理應用程序。MVC 模式的另一個優點是使用它可以更輕鬆地擴展控制器和視圖來處理其他類型 HTTP 請求,可以是 SOAP 服務,也可以是 XML API。

RSS MVC 模式

Struts、Ruby on Rails 和 Zend 框架全都擁護這種分層設計理念。如果發現 MVC 方法很吸引人,請研究用於 PHP 的 Zend 框架。但是,爲了減少樣例應用程序要求使用的附加軟件包的數目,我啓動了自己的 MVC 模式,如 清單 7 所示。

現在主代碼的大小減少了更多。它起到控制器的作用,該控制器將委派完成大多數工作來處理 HTTP 請求。它將構造一個域對象,該域對象將利用已經討論的相同業務規則,從域中檢索會話數據模型,然後將該模型轉換爲視圖類以轉換爲 HTML,該 HTML 將發送回客戶機。


清單 7. RSS 新聞控制器 news3.php

                
<?php
# news3.php
require_once "View.php"; 
require_once "RSSDomain.php";

putenv("LANG=de_DE");
$domain = new RSSDomain;
$model = $domain->getModel();
$view = new View($domain->getTemplate(), $model);
echo $view->asHTML();
?>

以前設計的相同的應用程序配置模式仍然控制着業務規則行爲。改變的只是新表示層處理 UI 的方法。該層不再使用 PHP 的 HTML 模板支持。相反,它依靠 XSL 轉換。域模型是一個可以序列化爲 XML 的嵌套對象的遞歸數據結構。視圖將導致 XSL 模板將會話數據的 XML 表示轉換爲返回到客戶機瀏覽器的本地化的 HTML。

表示層

清單 8 中顯示了構成表示層核心的 XML 模型和 XSL 模板。模型包括配置信息,例如新聞類型,尤其是這些選擇可以顯示給用戶的方法(//rss/newstypes/displaytypes)。模型還返回用戶的新聞類型選擇(//rss/userinput/newstype)和檢索的新聞標題及 URL(//rss/headlinelist/headline)。在用戶選擇的新聞類型無效的情況下,模型將返回一個錯誤代碼,而不是返回標題。XSL 模板將訪問返回的數據模型部分以構建顯示在客戶機瀏覽器中的 HTML。


清單 8. 樣例 XML 模型和 XSL 模板 (RSSView.xsl)

                
 <rss>
 	<newstypes>
		<displaytypes>Ausland, Technik</displaytypes>
		<typelist>
			<type>Technik</type>
			<type>Ausland</type>
		</typelist>
	</newstypes>
	<userinput>
		<newstype>Ausland</newstype>
	</userinput>
	<headlinelist>
		<headline>
		<hlink>http://de.news.yahoo.com/01112006/12/guatemala.html</hlink>
		<htitle>Guatemala und Venezuela halten Besprechungen</htitle>
		</headline>
		<headline>
		<hlink>http://de.news.yahoo.com/01112006/12/mandat.html</hlink>
		<htitle>Mandat einer Regierung in Afrika</htitle>
		</headline>
	</headlinelist>
</rss> 

---------------------------------------------------------------

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:variable name="pagetitle">Yahoo Schlagzeilen</xsl:variable>
<xsl:variable name="submitbutton">Hol Schlagzeilen</xsl:variable>
<xsl:variable name="displaytypes">
<xsl:value-of select="/rss/newstypes/displaytypes"/>
</xsl:variable>
<xsl:variable name="newstype">
<xsl:value-of select="/rss/userinput/newstype"/>
</xsl:variable>

<xsl:template match="/">
<html>
	<head>
		<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
		<title>
			<xsl:value-of select="$pagetitle"/>
		</title>
	</head>
	<body>
		<h1><xsl:value-of select="$pagetitle"/></h1>
		<p>
		Willkommen! Um den Yahoo Nachrichtleser zu gebrauchen, gib einen von den
		folgenden Nachrichttypen ein:  /
		<xsl:value-of select="/rss/newstypes/displaytypes"/>!
		</p>
		<!-- errors  -->
		<xsl:choose>
			<xsl:when test="rss/userinput/error/code">
				<p><b><font color="red">Falscher Typ</font></b></p>
			</xsl:when>
		</xsl:choose>
		<p>
		<form method = "POST">
			<input type = "text" name = "newstype" value = "{$newstype}" />
			<br/>
			<input type = "submit" value="{$submitbutton}" />
		</form>
		</p>
		<!-- headlines  -->
		<xsl:for-each select="/rss/headlinelist/headline">
			<a><xsl:attribute name="href">
			<xsl:value-of select="hlink"/>
			</xsl:attribute><xsl:value-of select="htitle"/></a>
			<br/>
		</xsl:for-each>
	</body>
</html>
</xsl:template>
</xsl:stylesheet>

使用這種方法,經過本地化的字符串不是通過諸如 gettext 之類的工具提取的。相反,每種語言環境都有自己的 XSL 模板。由於語言環境不再被提取,因此它應當可以更輕鬆地分佈維護應用程序的工作量。Web 開發人員、本地化團隊甚至產品經理都可以承擔實現適度的錯誤修正的職責並將請求限定到 UI

視圖類使用 PHP V5 附帶的 XSL 支持、數據模型和 XSL 模板來構建 HTML。PHP V4 則以一種不同的方法來實現此功能。在需要將舊的應用程序本地化的情況下,該方法也以註釋的形式顯示。在大多數情況下,XSLT 都會默認處於啓用狀態,但您可能需要在 PHP 安裝中啓用 XSLT 處理以使其全部運行。清單 9 顯示了 XSL 轉換。


清單 9. XSL 轉換 (View.php)

                
	public function asHTML() {
		$xml = new DomDocument;
		$modelxml = $this->model->asXML();
		#system('echo " ' . $modelxml . ' " > /tmp/l.txt');
		$xml->loadXML($modelxml);
		$xsl = new DomDocument;
		$xsl->load($this->template);
		$proc = new xsltprocessor;
		$proc->importStyleSheet($xsl);
		$html = $proc->transformToXML($xml);
		
#      Following is XSL transformation syntax for PHP4
#		$xh = xslt_create();
#		$arguments = array ('/_xml' => /
$this->model->asXML(),  '/_xsl' => $this->template);
#		$html = xslt_process($xh, 'arg:/_xml', $this->template, 
#                                          NULL, $arguments, $this->parameters);
#		xslt_free($xh);

		return $html;
	}

在包括了較大型團隊的情況下,提取字符串並通過主模板生成 XSL 模板可能仍有意義。這通常是由全球化管理系統 (GMS) 來執行的。然後 Web 開發人員只在以企業首選語言表示的默認 XSL 模板上工作,並且翻譯人員將使用管理系統的工具,並可能使用計算機輔助翻譯系統(如 SYSTRAN)來完成工作。

開發結束後並且到了發佈產品的時刻,典型的本地化過程可能會是這樣:

  • GMS 將從核心 XSL 模板中提取所有文本並且更新翻譯數據庫。
  • L10N 團隊將使用翻譯數據庫來翻譯新字符串並且重新翻譯更改的字符串。
  • GMS 通過翻譯數據庫重新構建每種語言環境的本地化 XSL 模板。

雖然使用 GMS 會帶來好處,但是對於一個小的團隊或變化不大的成熟的應用程序來說,使用 GMS 可能沒有什麼意義。對於所提及的所有工具來說,您應該清楚獲取、實現和支持您決定使用的工具的收益和開銷。

下載

描述 名字 大小 下載方法
樣例腳本1 os-php-intl.zip 12KB HTTP
POST['newstype']) ?
對應用程序的本地化或者可以事先進行規劃,或者也可以過後追悔莫及。本文帶您探索有助於改進本地化過程或進行本地化規劃的技術和工具,如gettext、XML、XSLT 及設計模式等。

評估應用程序

本地化的要求非常模糊,如同說 “使應用程序準備好在德國使用” 一樣。但是即使當要求看似很詳細的時候,您還是可以發現產品經理沒考慮到的事情。

例如,就拿清單 1 中所示的標準的 Yahoo! RSS 新聞閱讀器應用程序來說。當頁面第一次被調用時,將顯示默認的標題列表,並且有一個表單字段,您可以在其中鍵入選擇的新聞類別,然後再重新提交頁面。該應用程序將驗證鍵入的類別,如果類別無效的話將顯示錯誤消息,或者顯示所請求類別的標題。


清單 1. 來自 Yahoo 的 RSS 新聞!

___FCKpd___0

雖然此應用程序很簡單,但是它說明了在本地化過程中出現的很多問題。它還反映了任何腳本語言的一些優缺點。

您總是可以按成本價迅速推出產品。 用戶界面 (UI)、業務邏輯和配置,或缺少其中一些元素,將它們混合在一起,而不考慮維護或擴展具有新功能的頁面。

在對此頁面進行德語本地化以及可能的其他語言本地化時,會遇到幾個障礙:

  • 應當重構代碼以分離各個應用層。
  • 必須提取並翻譯 UI 文本,例如標題、內容和錯誤消息。
  • 必須將諸如 Submit 按鈕之類的表單控件本地化。
  • 應用程序需要一種定義目標語言環境的方法。
  • 用戶輸入要求及驗證會因語言環境的不同而有所變化。
  • 考慮依賴於語言環境的業務規則,例如 Yahoo! RSS 提要的 URL;目標和語法會因國家或地區的不同而有所不同。
  • 對在各種語言環境中支持配置和控制應用程序域行爲的框架的需要更加迫切。

完成所有這些工作所需的投入很容易與原始應用程序的成本持平,或超出原始應用程序的成本 —— 全面考慮需要面對很多困難。因此,您的團隊必須對這些障礙有所準備,無論是在應用程序完成之前還是完成之後。





回頁首


本地化術語

如果您要在項目中與翻譯人員協作,那麼最好確保您瞭解一些可能在與翻譯人員的談話中會遇到的術語。表 1 定義了語言學家和專業翻譯人員使用的一些常用術語。


表 1. 本地化術語

術語 含義
語言環境 語言與國家或地區的組合 —— 例如 en_US、en_GB、de_DE
國際化 (I18N) 規劃、設計和準備要本地化的應用程序
本地化 (L10N) 識別並翻譯 (T9N) 用於目標語言環境的應用程序 UI
外在化(字符串提取) 提取程序字符串以供翻譯的過程




回頁首


花樣翻新的本地化

清單 2 顯示了經過重構翻新以支持本地化後的 RSS 應用程序。功能邏輯和本地化框架被抽象到處理程序類中。主代碼中需要完成的工作是構造頁面處理程序對象、HTML 模板並調用處理程序的 accessor 方法來填充 HTML 模板的動態部分。


清單 2. 經過本地化的 RSS 新聞

___FCKpd___1

重構的優點是程序員可以更輕鬆地維護代碼。也就是說,UI 現在是否更具有可維護性是有疑義的,因爲它缺少語言環境,並且 HTML 的絕大部分仍嵌入在 PHP 代碼中。

PHP 程序員是否會信任 Web 開發人員所做的這些類型的更改?讓後端開發人員處理小的 UI 更改請求需要花費多少成本?稍後,我將展示擴展樣式表語言轉換(Extensible Stylesheet Language Transformation,XSLT)如何更好地分離應用層。

構造函數

讓我們從處理程序類的構造函數開始(參見 清單 3)來看看如何爲本地化翻新頁面。當頁面處理程序被實例化後,構造函數將確定相應的語言環境,檢索該語言環境的配置設置,驗證任何用戶輸入,根據用戶當前的語言環境計算所有以前的靜態內容,然後驗證任何用戶輸入。(要獲得源代碼,請參閱 下載。)


清單 3. RSSHandler.php

___FCKpd___2

在本例中,爲了簡單起見,語言環境被硬編碼爲 de_DE。在現實情況中,您會需要根據業務要求設置語言環境。確定正確的語言環境有兩種常用方法:檢查請求 URL(例如,www.ebay.de、amazon.fr)或簡單地詢問用戶並在其瀏覽器中設置首選 cookie。

檢索配置參數

確定了語言環境後,處理程序將檢索德國配置參數。在本例中,配置包括使用 PEAR 軟件包 (Config.php)、XML 配置文件 (RSSConfig.xml)、特定於應用程序域的包裝器 (RSSConfig.php) 和一個簡單的裝飾類來爲一些配置參數添加 HTML 標記 (Configdecorator.php)。

清單 4 中所示的配置文件將以 XML 形式存儲其信息。它用於指定字符串提取的上下文(//conf/textdomain)—— 依賴於語言環境的組件的位置及消息文件的名稱。

注:如果下載並嘗試運行樣例,請確保更改路徑使其指向提取並翻譯後的字符串以匹配您的環境。

配置文件還將告訴應用程序如何構造正確的 Yahoo! 新聞提要 URL (//conf/de_DE/baseurl)、如何驗證用戶對新聞提要類型做出的選擇 (//conf/de_DE/newtypes) 以及在用戶沒有做出選擇的情況下哪類新聞應當爲默認值。


清單 4. Configuration.xml

___FCKpd___3

您可以通過添加 “默認” 語言環境使配置更加健壯。然後,如果應用程序嘗試顯示無效的語言環境,則要始終保證一些合理的應用程序行爲。您還可以擴展配置以容納其他應用程序形式,例如品牌聯合或基於用戶權限的應用程序限制。

餘下的大多數處理程序對象包括衍生頁面中與每種語言環境相對應的文本部分,並且提供公共的 accessor 方法,這些方法使這些經過翻譯的文本可用於 HTML 模板。

gettext 提取框架

應用程序將使用一個名爲 gettext 的開源字符串提取框架以實例化經過翻譯的字符串。此框架有幾個優點:

  • 它是免費的。
  • 它可以在各種平臺上運行。
  • 它可以使用許多編程語言,包括 PHP。
  • 它特別適用於翻新工作。

要使用 gettext,請執行以下步驟:

  1. 爲必須支持的所有語言環境創建目錄結構。
  2. 通過將字符串移入特定函數 gettext() 的參數來標記字符串。
  3. 運行 xgettext 命令行實用程序將字符串提取到消息文件中。
  4. 將得到的消息文件複製到每個語言環境的專用目錄下。
  5. 編輯本地版本的消息文件並翻譯文本。
  6. 運行 msgfmt 命令行實用程序以創建在運行時使用的本地化的消息數據庫。

使用 gettext() 函數的目的很明顯 —— 在運行時檢索本地化的文本,認識到這一點很重要。但同等重要的是事實上它還是用於文本提取的 標記xgettext 實用程序將查找此函數標記的字符串。

清單 5 中顯示了樣例應用程序的所有軟件組件,包括在應用程序配置中定義的目錄結構。每個 gettext 實現都要求使用與此類似的目錄結構。無需爲默認語言環境創建目錄樹或消息數據庫;用於該語言環境的字符串已經被嵌入到代碼中。但是需要編輯 RSSConfig.xml 文件以正確標識指向 gettext 框架中這些文件的完整路徑。


清單 5. 目錄結構

___FCKpd___4

翻譯消息文件

在德語消息文件中,翻譯人員必須提供的部分被標記爲粗體。換言之,翻譯人員必須填空。當翻譯人員首次打開消息文件時,這些部分將爲空,並且翻譯人員必須指定要使用的字符編碼(在本例中爲 Latin-1)和翻譯。消息 ID (msgid) 是用於提取而調用 gettext() 函數進行標記的原始文本。消息字符串 (msgstr) 是必須用目標語言顯示的字符串。清單 6 顯示了當用戶指定了錯誤的消息類型時錯誤消息的翻譯。


清單 6. 德語消息文件 messages.po.de

___FCKpd___5

如果任何已提取的字符串的文本在任何時候發生更改,則在每次生成消息文件時將創建新消息 ID。每次添加或更改字符串時,都應當重新生成消息文件,否則將在目標語言環境顯示未翻譯的新文本。

在生產環境中,L10N 團隊通常會執行所有這些任務(除了準備源代碼以外)。但是這不意味着您可以完全不受語言問題的影響。將應用程序本地化時需要切記以下要點:

  • 不要將功能信息嵌入到字符串中。
  • 在完整的句子中使用 printf 標記來標記動態內容而不要將句子分割爲多個字符串。記住不同語言之間的句子中的語序是不同的;您可以讓翻譯人員來控制語序。如果字符串包含多個動態元素,則 msgfmt 支持擴展標記語法,該語法允許您指定字符串中每個動態元素的位置。在翻譯過程中可以輕鬆地更改元素的順序。您可以在任意一本 gettext 的聯機手冊中瞭解關於位置語法的更多信息(請參閱 參考資料)。
  • 確保字符串具有足夠的有意義的上下文。記住翻譯人員將只能看到字符串 —— 而不是運行的應用程序。

注:有關將軟件本地化時在語言方面的更多建議,請參閱 參考資料

當添加新文本或重述現有文本時,本地化團隊可以使用其他 gettext 實用程序將新字符串或更改的字符串合併到現有消息文件中,從而免去重新翻譯的需求。





回頁首


設計本地化

在大多數情況下按照上述方法處理本地化很可能足夠優秀。但是,隨着範圍的擴大,考慮使用設計模式來設計應用程序會十分有意義。最廣泛使用的一種模式是 Model-View-Controller (MVC)。此模式鼓勵您分層(表示層、域層、數據訪問層)處理應用程序。MVC 模式的另一個優點是使用它可以更輕鬆地擴展控制器和視圖來處理其他類型 HTTP 請求,可以是 SOAP 服務,也可以是 XML API。

RSS MVC 模式

Struts、Ruby on Rails 和 Zend 框架全都擁護這種分層設計理念。如果發現 MVC 方法很吸引人,請研究用於 PHP 的 Zend 框架。但是,爲了減少樣例應用程序要求使用的附加軟件包的數目,我啓動了自己的 MVC 模式,如 清單 7 所示。

現在主代碼的大小減少了更多。它起到控制器的作用,該控制器將委派完成大多數工作來處理 HTTP 請求。它將構造一個域對象,該域對象將利用已經討論的相同業務規則,從域中檢索會話數據模型,然後將該模型轉換爲視圖類以轉換爲 HTML,該 HTML 將發送回客戶機。


清單 7. RSS 新聞控制器 news3.php

___FCKpd___6

以前設計的相同的應用程序配置模式仍然控制着業務規則行爲。改變的只是新表示層處理 UI 的方法。該層不再使用 PHP 的 HTML 模板支持。相反,它依靠 XSL 轉換。域模型是一個可以序列化爲 XML 的嵌套對象的遞歸數據結構。視圖將導致 XSL 模板將會話數據的 XML 表示轉換爲返回到客戶機瀏覽器的本地化的 HTML。

表示層

清單 8 中顯示了構成表示層核心的 XML 模型和 XSL 模板。模型包括配置信息,例如新聞類型,尤其是這些選擇可以顯示給用戶的方法(//rss/newstypes/displaytypes)。模型還返回用戶的新聞類型選擇(//rss/userinput/newstype)和檢索的新聞標題及 URL(//rss/headlinelist/headline)。在用戶選擇的新聞類型無效的情況下,模型將返回一個錯誤代碼,而不是返回標題。XSL 模板將訪問返回的數據模型部分以構建顯示在客戶機瀏覽器中的 HTML。


清單 8. 樣例 XML 模型和 XSL 模板 (RSSView.xsl)

___FCKpd___7

使用這種方法,經過本地化的字符串不是通過諸如 gettext 之類的工具提取的。相反,每種語言環境都有自己的 XSL 模板。由於語言環境不再被提取,因此它應當可以更輕鬆地分佈維護應用程序的工作量。Web 開發人員、本地化團隊甚至產品經理都可以承擔實現適度的錯誤修正的職責並將請求限定到 UI

視圖類使用 PHP V5 附帶的 XSL 支持、數據模型和 XSL 模板來構建 HTML。PHP V4 則以一種不同的方法來實現此功能。在需要將舊的應用程序本地化的情況下,該方法也以註釋的形式顯示。在大多數情況下,XSLT 都會默認處於啓用狀態,但您可能需要在 PHP 安裝中啓用 XSLT 處理以使其全部運行。清單 9 顯示了 XSL 轉換。


清單 9. XSL 轉換 (View.php)

___FCKpd___8

在包括了較大型團隊的情況下,提取字符串並通過主模板生成 XSL 模板可能仍有意義。這通常是由全球化管理系統 (GMS) 來執行的。然後 Web 開發人員只在以企業首選語言表示的默認 XSL 模板上工作,並且翻譯人員將使用管理系統的工具,並可能使用計算機輔助翻譯系統(如 SYSTRAN)來完成工作。

開發結束後並且到了發佈產品的時刻,典型的本地化過程可能會是這樣:

  • GMS 將從核心 XSL 模板中提取所有文本並且更新翻譯數據庫。
  • L10N 團隊將使用翻譯數據庫來翻譯新字符串並且重新翻譯更改的字符串。
  • GMS 通過翻譯數據庫重新構建每種語言環境的本地化 XSL 模板。

雖然使用 GMS 會帶來好處,但是對於一個小的團隊或變化不大的成熟的應用程序來說,使用 GMS 可能沒有什麼意義。對於所提及的所有工具來說,您應該清楚獲取、實現和支持您決定使用的工具的收益和開銷。

下載

描述 名字 大小 下載方法
樣例腳本1 os-php-intl.zip 12KB HTTP
POST['newstype'] : "tech"); $error = null; switch($newstype) { case 'world': case 'tech': break; default: $error = 'Invalid news type.'; break; } ?> <html> <head> <title>RSS Feed from Yahoo News</title> </head> <body> <h1>RSS Feed from Yahoo News</h1> <p> Welcome to the Yahoo RSS news reader. To view headlines for different kinds of news enter the news type in the text box below and then submit the form. Valid news types are 'tech' and 'world'. </p> <p> <form method = "POST"> <?php if (isset($error)) { echo '<br/><font color = "red">' . $error . '</font><br/>'; } ?> <input type = "text" name = "newstype" value = "<?php echo $newstype ?>" /> <br> <input type = "submit"> </form> </p> <?php $url = "http://rss.news.yahoo.com/rss/" . $newstype; $rss = new XML_RSS($url); $rss->parse(); echo "<ul>/n"; foreach ($rss->getItems() as $item) { echo "<li><a href=/"" . $item['link'] . "/">" . $item['title'] . "</a></li>/n"; } echo "</ul>/n"; ?> </body> </html>

雖然此應用程序很簡單,但是它說明了在本地化過程中出現的很多問題。它還反映了任何腳本語言的一些優缺點。

您總是可以按成本價迅速推出產品。 用戶界面 (UI)、業務邏輯和配置,或缺少其中一些元素,將它們混合在一起,而不考慮維護或擴展具有新功能的頁面。

在對此頁面進行德語本地化以及可能的其他語言本地化時,會遇到幾個障礙:

  • 應當重構代碼以分離各個應用層。
  • 必須提取並翻譯 UI 文本,例如標題、內容和錯誤消息。
  • 必須將諸如 Submit 按鈕之類的表單控件本地化。
  • 應用程序需要一種定義目標語言環境的方法。
  • 用戶輸入要求及驗證會因語言環境的不同而有所變化。
  • 考慮依賴於語言環境的業務規則,例如 Yahoo! RSS 提要的 URL;目標和語法會因國家或地區的不同而有所不同。
  • 對在各種語言環境中支持配置和控制應用程序域行爲的框架的需要更加迫切。

完成所有這些工作所需的投入很容易與原始應用程序的成本持平,或超出原始應用程序的成本 —— 全面考慮需要面對很多困難。因此,您的團隊必須對這些障礙有所準備,無論是在應用程序完成之前還是完成之後。





回頁首


本地化術語

如果您要在項目中與翻譯人員協作,那麼最好確保您瞭解一些可能在與翻譯人員的談話中會遇到的術語。表 1 定義了語言學家和專業翻譯人員使用的一些常用術語。


表 1. 本地化術語

術語 含義
語言環境 語言與國家或地區的組合 —— 例如 en_US、en_GB、de_DE
國際化 (I18N) 規劃、設計和準備要本地化的應用程序
本地化 (L10N) 識別並翻譯 (T9N) 用於目標語言環境的應用程序 UI
外在化(字符串提取) 提取程序字符串以供翻譯的過程




回頁首


花樣翻新的本地化

清單 2 顯示了經過重構翻新以支持本地化後的 RSS 應用程序。功能邏輯和本地化框架被抽象到處理程序類中。主代碼中需要完成的工作是構造頁面處理程序對象、HTML 模板並調用處理程序的 accessor 方法來填充 HTML 模板的動態部分。


清單 2. 經過本地化的 RSS 新聞

___FCKpd___1

重構的優點是程序員可以更輕鬆地維護代碼。也就是說,UI 現在是否更具有可維護性是有疑義的,因爲它缺少語言環境,並且 HTML 的絕大部分仍嵌入在 PHP 代碼中。

PHP 程序員是否會信任 Web 開發人員所做的這些類型的更改?讓後端開發人員處理小的 UI 更改請求需要花費多少成本?稍後,我將展示擴展樣式表語言轉換(Extensible Stylesheet Language Transformation,XSLT)如何更好地分離應用層。

構造函數

讓我們從處理程序類的構造函數開始(參見 清單 3)來看看如何爲本地化翻新頁面。當頁面處理程序被實例化後,構造函數將確定相應的語言環境,檢索該語言環境的配置設置,驗證任何用戶輸入,根據用戶當前的語言環境計算所有以前的靜態內容,然後驗證任何用戶輸入。(要獲得源代碼,請參閱 下載。)


清單 3. RSSHandler.php

___FCKpd___2

在本例中,爲了簡單起見,語言環境被硬編碼爲 de_DE。在現實情況中,您會需要根據業務要求設置語言環境。確定正確的語言環境有兩種常用方法:檢查請求 URL(例如,www.ebay.de、amazon.fr)或簡單地詢問用戶並在其瀏覽器中設置首選 cookie。

檢索配置參數

確定了語言環境後,處理程序將檢索德國配置參數。在本例中,配置包括使用 PEAR 軟件包 (Config.php)、XML 配置文件 (RSSConfig.xml)、特定於應用程序域的包裝器 (RSSConfig.php) 和一個簡單的裝飾類來爲一些配置參數添加 HTML 標記 (Configdecorator.php)。

清單 4 中所示的配置文件將以 XML 形式存儲其信息。它用於指定字符串提取的上下文(//conf/textdomain)—— 依賴於語言環境的組件的位置及消息文件的名稱。

注:如果下載並嘗試運行樣例,請確保更改路徑使其指向提取並翻譯後的字符串以匹配您的環境。

配置文件還將告訴應用程序如何構造正確的 Yahoo! 新聞提要 URL (//conf/de_DE/baseurl)、如何驗證用戶對新聞提要類型做出的選擇 (//conf/de_DE/newtypes) 以及在用戶沒有做出選擇的情況下哪類新聞應當爲默認值。


清單 4. Configuration.xml

___FCKpd___3

您可以通過添加 “默認” 語言環境使配置更加健壯。然後,如果應用程序嘗試顯示無效的語言環境,則要始終保證一些合理的應用程序行爲。您還可以擴展配置以容納其他應用程序形式,例如品牌聯合或基於用戶權限的應用程序限制。

餘下的大多數處理程序對象包括衍生頁面中與每種語言環境相對應的文本部分,並且提供公共的 accessor 方法,這些方法使這些經過翻譯的文本可用於 HTML 模板。

gettext 提取框架

應用程序將使用一個名爲 gettext 的開源字符串提取框架以實例化經過翻譯的字符串。此框架有幾個優點:

  • 它是免費的。
  • 它可以在各種平臺上運行。
  • 它可以使用許多編程語言,包括 PHP。
  • 它特別適用於翻新工作。

要使用 gettext,請執行以下步驟:

  1. 爲必須支持的所有語言環境創建目錄結構。
  2. 通過將字符串移入特定函數 gettext() 的參數來標記字符串。
  3. 運行 xgettext 命令行實用程序將字符串提取到消息文件中。
  4. 將得到的消息文件複製到每個語言環境的專用目錄下。
  5. 編輯本地版本的消息文件並翻譯文本。
  6. 運行 msgfmt 命令行實用程序以創建在運行時使用的本地化的消息數據庫。

使用 gettext() 函數的目的很明顯 —— 在運行時檢索本地化的文本,認識到這一點很重要。但同等重要的是事實上它還是用於文本提取的 標記xgettext 實用程序將查找此函數標記的字符串。

清單 5 中顯示了樣例應用程序的所有軟件組件,包括在應用程序配置中定義的目錄結構。每個 gettext 實現都要求使用與此類似的目錄結構。無需爲默認語言環境創建目錄樹或消息數據庫;用於該語言環境的字符串已經被嵌入到代碼中。但是需要編輯 RSSConfig.xml 文件以正確標識指向 gettext 框架中這些文件的完整路徑。


清單 5. 目錄結構

___FCKpd___4

翻譯消息文件

在德語消息文件中,翻譯人員必須提供的部分被標記爲粗體。換言之,翻譯人員必須填空。當翻譯人員首次打開消息文件時,這些部分將爲空,並且翻譯人員必須指定要使用的字符編碼(在本例中爲 Latin-1)和翻譯。消息 ID (msgid) 是用於提取而調用 gettext() 函數進行標記的原始文本。消息字符串 (msgstr) 是必須用目標語言顯示的字符串。清單 6 顯示了當用戶指定了錯誤的消息類型時錯誤消息的翻譯。


清單 6. 德語消息文件 messages.po.de

___FCKpd___5

如果任何已提取的字符串的文本在任何時候發生更改,則在每次生成消息文件時將創建新消息 ID。每次添加或更改字符串時,都應當重新生成消息文件,否則將在目標語言環境顯示未翻譯的新文本。

在生產環境中,L10N 團隊通常會執行所有這些任務(除了準備源代碼以外)。但是這不意味着您可以完全不受語言問題的影響。將應用程序本地化時需要切記以下要點:

  • 不要將功能信息嵌入到字符串中。
  • 在完整的句子中使用 printf 標記來標記動態內容而不要將句子分割爲多個字符串。記住不同語言之間的句子中的語序是不同的;您可以讓翻譯人員來控制語序。如果字符串包含多個動態元素,則 msgfmt 支持擴展標記語法,該語法允許您指定字符串中每個動態元素的位置。在翻譯過程中可以輕鬆地更改元素的順序。您可以在任意一本 gettext 的聯機手冊中瞭解關於位置語法的更多信息(請參閱 參考資料)。
  • 確保字符串具有足夠的有意義的上下文。記住翻譯人員將只能看到字符串 —— 而不是運行的應用程序。

注:有關將軟件本地化時在語言方面的更多建議,請參閱 參考資料

當添加新文本或重述現有文本時,本地化團隊可以使用其他 gettext 實用程序將新字符串或更改的字符串合併到現有消息文件中,從而免去重新翻譯的需求。





回頁首


設計本地化

在大多數情況下按照上述方法處理本地化很可能足夠優秀。但是,隨着範圍的擴大,考慮使用設計模式來設計應用程序會十分有意義。最廣泛使用的一種模式是 Model-View-Controller (MVC)。此模式鼓勵您分層(表示層、域層、數據訪問層)處理應用程序。MVC 模式的另一個優點是使用它可以更輕鬆地擴展控制器和視圖來處理其他類型 HTTP 請求,可以是 SOAP 服務,也可以是 XML API。

RSS MVC 模式

Struts、Ruby on Rails 和 Zend 框架全都擁護這種分層設計理念。如果發現 MVC 方法很吸引人,請研究用於 PHP 的 Zend 框架。但是,爲了減少樣例應用程序要求使用的附加軟件包的數目,我啓動了自己的 MVC 模式,如 清單 7 所示。

現在主代碼的大小減少了更多。它起到控制器的作用,該控制器將委派完成大多數工作來處理 HTTP 請求。它將構造一個域對象,該域對象將利用已經討論的相同業務規則,從域中檢索會話數據模型,然後將該模型轉換爲視圖類以轉換爲 HTML,該 HTML 將發送回客戶機。


清單 7. RSS 新聞控制器 news3.php

___FCKpd___6

以前設計的相同的應用程序配置模式仍然控制着業務規則行爲。改變的只是新表示層處理 UI 的方法。該層不再使用 PHP 的 HTML 模板支持。相反,它依靠 XSL 轉換。域模型是一個可以序列化爲 XML 的嵌套對象的遞歸數據結構。視圖將導致 XSL 模板將會話數據的 XML 表示轉換爲返回到客戶機瀏覽器的本地化的 HTML。

表示層

清單 8 中顯示了構成表示層核心的 XML 模型和 XSL 模板。模型包括配置信息,例如新聞類型,尤其是這些選擇可以顯示給用戶的方法(//rss/newstypes/displaytypes)。模型還返回用戶的新聞類型選擇(//rss/userinput/newstype)和檢索的新聞標題及 URL(//rss/headlinelist/headline)。在用戶選擇的新聞類型無效的情況下,模型將返回一個錯誤代碼,而不是返回標題。XSL 模板將訪問返回的數據模型部分以構建顯示在客戶機瀏覽器中的 HTML。


清單 8. 樣例 XML 模型和 XSL 模板 (RSSView.xsl)

___FCKpd___7

使用這種方法,經過本地化的字符串不是通過諸如 gettext 之類的工具提取的。相反,每種語言環境都有自己的 XSL 模板。由於語言環境不再被提取,因此它應當可以更輕鬆地分佈維護應用程序的工作量。Web 開發人員、本地化團隊甚至產品經理都可以承擔實現適度的錯誤修正的職責並將請求限定到 UI

視圖類使用 PHP V5 附帶的 XSL 支持、數據模型和 XSL 模板來構建 HTML。PHP V4 則以一種不同的方法來實現此功能。在需要將舊的應用程序本地化的情況下,該方法也以註釋的形式顯示。在大多數情況下,XSLT 都會默認處於啓用狀態,但您可能需要在 PHP 安裝中啓用 XSLT 處理以使其全部運行。清單 9 顯示了 XSL 轉換。


清單 9. XSL 轉換 (View.php)

___FCKpd___8

在包括了較大型團隊的情況下,提取字符串並通過主模板生成 XSL 模板可能仍有意義。這通常是由全球化管理系統 (GMS) 來執行的。然後 Web 開發人員只在以企業首選語言表示的默認 XSL 模板上工作,並且翻譯人員將使用管理系統的工具,並可能使用計算機輔助翻譯系統(如 SYSTRAN)來完成工作。

開發結束後並且到了發佈產品的時刻,典型的本地化過程可能會是這樣:

  • GMS 將從核心 XSL 模板中提取所有文本並且更新翻譯數據庫。
  • L10N 團隊將使用翻譯數據庫來翻譯新字符串並且重新翻譯更改的字符串。
  • GMS 通過翻譯數據庫重新構建每種語言環境的本地化 XSL 模板。

雖然使用 GMS 會帶來好處,但是對於一個小的團隊或變化不大的成熟的應用程序來說,使用 GMS 可能沒有什麼意義。對於所提及的所有工具來說,您應該清楚獲取、實現和支持您決定使用的工具的收益和開銷。

下載

描述 名字 大小 下載方法
樣例腳本1 os-php-intl.zip 12KB HTTP
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章