设为首页 收藏本站
查看: 562|回复: 0

[经验分享] PHP getext实现多语言

[复制链接]

尚未签到

发表于 2015-8-28 12:11:28 | 显示全部楼层 |阅读模式
以下都转载与http://plog.longwin.com.tw

在 Windows 使用 GetText
  要在 Windows 使用 xgettext, msgmerge, msgfmt ... 等, 要安裝哪些東西?
Windows 的 GetText 工具安裝

  • 於 GetText for Windows 下載 Binaries 版, 安裝即可. (假設安裝於 C:\gettext)
GetText 所需相關 Library 安裝

  • 上述套件下載後, 於 Windows XP 會缺下述兩個 Library:

    • libexpat.dll
    • libiconv2.dll

  • 可自行去尋找, 或者 直接下載 : gettext-dll.tgz
  • 將這兩個檔案放到 C:\gettext\bin\ 即可.
GetText 工具使用

  • C:\gettext\bin\xgettext.exe --from-code=UTF-8 -d hello hello.php
  • C:\gettext\bin\msgmerge.exe -o hello.po locale/zh_TW/LC_MESSAGES/hello.po hello.po
  • C:\gettext\bin\msgfmt.exe -o locale/zh_TW/LC_MESSAGES/hello.mo hello.po
使用 gettext 來實做 PHP 多國語系支援(I18N)
  要做多國語系支援的網站或程式有很多方式, 常見的是設某種國家的語系檔, 然後檔案內都是變數, 之後程式依照使用者的語系的, 去讀語系檔, 以此來達成多國語系.
  而 gettext 是另一種標準的方案, 可以 ls /usr/share/locale/zh_TW/LC_MESSAGES 看看, /usr/share/locale 放著各種語系的翻譯檔(翻譯系統程式, ex: apt.mo, dpkg.mo)(*.mo是編譯過的翻譯檔).
  現在來用 php + gettext 實做多國語系的支援吧~
  通常多國語系有兩種模式

  • 每個檔案一個翻譯檔
  • 所有檔案一個翻譯檔
  下面會先做 每個檔案一個翻譯檔 的方法, 最下面才是 所有檔案一個翻譯檔 的方法(基本上都大同小異就是了).
  以下 以 Debian Linux 為例(/etc/locale.gen).
前置準備(程式, 設定 /etc/locale.gen)
  需要下述程式

  • xgettext - extract gettext strings from source
  • msgfmt - compile message catalog to binary format
  然後要設定 vim /etc/locale.gen, 檔案內容如下:(看你的語系要支援哪些, 就要有哪些)
zh_TW BIG5
en_US UTF-8
zh_CN UTF-8
zh_TW UTF-8
  /etc/locale.gen 如果有改動, 記得要 sudo locale-gen, 不然不會生效 :)
每個檔案一個翻譯檔 設置法(語系: 英文(en_US), 簡體(zh_CN), 正體(zh_TW))
建立基本架構
  PS: 下述建立基本結構, 懶得做可直接下載 gettext_example.tgz, 解壓縮就有基本架構了.
  先到要建立多國語系的 Project 目錄下
mkdir -p locale/zh_TW/LC_MESSAGES
mkdir -p locale/zh_CN/LC_MESSAGES
mkdir -p locale/en_US/LC_MESSAGES
  在此以 hello.php 為例, 建立 hello.php 檔, 內容如下:(PHP 主要用到 putenv, setlocale, bindtextdomain,textdomain, gettext 的 function)
  程式(hello.php, 或其它自己建的程式)注意下述幾點即可:

  • 語系切換主要是靠 putenv, setlocale.(程式裡面現在是用 $lang 去切換語系, 如何切換可再想更好的方法)
  • 裡面的 putenv, setlocale 指定的值, 會對應到 /etc/locale.gen 的值, 如果 locale.gen 沒有, 在 putenv, setlocale 設了也沒有用.
  • PACKAGE 那個變數, 不用 define 也無所謂, 主要是當成 Project name 來用, 到時後翻譯檔建好後, 此名稱就不能再修改(修改翻譯檔需要全部重建(po, mo 檔重建))
  • gettext() 包起來的就是會被抽取出來的字, 可以用較簡短的寫法 _() 即可.
將文字取出, 產生 po 檔


  • xgettext -d hello hello.php # -d hello => 產生 hello.po 檔(-d --default-domain=NAME, 跟 bindtextdomain, textdomain 的 PACKAGE 對應, 也和 po 的檔名相對應)
  • PS: 如果 _(), gettext() 包的不只是英文, 需要加 --from-code=encoding, ex: xgettext --from-code=UTF-8 -d hello hello.php
  • cp hello.po locale/zh_TW/LC_MESSAGES/hello.po
  • cp hello.po locale/zh_CN/LC_MESSAGES/hello.po
  • cp hello.po locale/en_US/LC_MESSAGES/hello.po
  • PS: locale/*/LC_MESSAGES/*.po 都是不需要的, 只需要 mo 檔, 但是放 po 在裡面是之後要修改並產生會比較方便.
修改 hello.po 檔(翻譯此檔案)

  • 翻譯主要就是要翻譯 locale/*/LC_MESSAGE/*.po 檔
  • vim locale/zh_TW/LC_MESSAGES/hello.po
  • vim locale/zh_CN/LC_MESSAGES/hello.po
  • vim locale/en_US/LC_MESSAGES/hello.po
  修改 hello.po 上面的 header 處, 做以下幾個步驟:(1~5 不做沒關係, 但是 第 6 步 一定要做)

  • 移除 #, fuzzy
  • "Project-Id-Version: PACKAGE VERSION\n" => PACKAGE VERSION 改成自己 Project name 和版本, ex: hello-0.1
  • "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" => ex: "PO-Revision-Date: 2007-09-16 20:08+0800\n"
  • "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" => ex: "Last-Translator: Jon <jon@email_address>\n"
  • "Language-Team: LANGUAGE <LL@li.org>\n" => ex: "Language-Team: Chinese <LL@li.org>\n"
  • 將 "Content-Type: text/plain; charset=CHARSET\n" 修改成"Content-Type: text/plain; charset=UTF-8\n"
  • 翻譯會看到 msgid "Hello World!",下面有 msgstr "",就是要修改 msgstr這邊,改成要翻譯的字串.
  • ex: msgid "Hello World!", msgstr "嗨, 世界!",這樣子之後 "Hello World!" 就都會被換成"嗨, 世界!"
產生 hello.mo 檔


  • msgfmt -o hello.mo hello.po # 這個不是重點, 下面三行才是重點, 直接產生各種翻譯完的 mo 檔
  • msgfmt -o locale/zh_TW/LC_MESSAGES/hello.mo locale/zh_TW/LC_MESSAGES/hello.po
  • msgfmt -o locale/zh_CN/LC_MESSAGES/hello.mo locale/zh_CN/LC_MESSAGES/hello.po
  • msgfmt -o locale/en_US/LC_MESSAGES/hello.mo locale/en_US/LC_MESSAGES/hello.po
  • gettext 看的是 mo 檔, 不是 po 檔 :)
測試
  連到 http://Project_URL/hello.php,然後下面有三個連結, 都點點看, 應該就會看到各種不同語系的呈現了.
另一種設置法 所有檔案使用同一個翻譯檔(messages.po)

  • xgettext *.php (第一次建議要加 -d NAME, ex: xgettext -d messages *.php)
  • PS: 如果 _(), gettext() 包的不只是英文, 需要加 --from-code=encoding, ex: xgettext --from-code=UTF-8 *.php
  • vim messages.po # 刪掉 #,fuzzy , 並修改表頭那些資訊
  • msgfmt -cv messages.po # -cv 是 check 並列出來有哪些錯誤(若都不改表頭, 會出現不少錯誤)
  • cp messages.po locale/zh_TW/LC_MESSAGES/ # 同理, 修改完 po 檔 cp 到 zh_CN/en_US
  • msgfmt -o locale/zh_TW/LC_MESSAGES/messages.mo locale/zh_TW/LC_MESSAGES/messages.po # 同理, 可做 zh_CN/en_US
  • 再來同上面的測試, 一樣測法.
修改檔案, 將新的翻譯合併(msgmerge)回原本的翻譯檔(po檔)

  • 現在將 hello.php 裡面的 33, 34 行註解拿掉, 主要是 "echo _("New, line!");" 這行, 這代表有新增一個需要翻譯的資料.
  • xgettext -d hello hello.php
  • vim hello.po # 改 Content-Type 為 UTF-8, 要做翻譯可於此處就先做
  • msgmerge -o locale/zh_TW/LC_MESSAGES/hello.po locale/zh_TW/LC_MESSAGES/hello.po hello.po # 合併到原始翻譯檔
  • vim locale/zh_TW/LC_MESSAGES/hello.po # 若上一步沒翻譯, 則於此時做翻譯
  • msgfmt -o locale/zh_TW/LC_MESSAGES/hello.mo locale/zh_TW/LC_MESSAGES/hello.po
  • 這樣子就更新完成囉!
快速整理流程和做法

  • xgettext -d hello hello.php 或 xgettext *.php (若包含非英文需加上 --from-code=UTF-8)
  • vim *.po # 最懶的改法只要將 CHARSET 改成 UTF-8 即可.
  • msgfmt -o hello.mo hello.po 或 msgfmt -o messages.mo messages.po (或 msgfmt -cv messages.po, -cv 會做較嚴格的檢查)
  • 將 *.mo 放到 locale/*/LC_MESSAGES/ 去即可.
快速整理 更新合併 po 檔流程

  • xgettext -d hello hello.php 或 xgettext *.php (若包含非英文需加上 --from-code=UTF-8)
  • vim *.po # 將 CHARSET 改成 UTF-8, 並對新的做翻譯
  • msgmerge -o hello.po locale/zh_TW/LC_MESSAGES/hello.po hello.po #合併, msgmerge -o "合併完要存的檔名" "現在使用的檔(要跟此檔合併)" "新的po檔案"
  • vim *.po # 找看看有沒有 "#,fuzzy", 有的話就手動處理
  • msgfmt -o hello.mo hello.po # 建立 mo 檔
  • 將 *.mo 放到 locale/*/LC_MESSAGES/ 去即完成更新
附註

  • 每次編 po 檔時, 請都要注意 #, fuzzy 的字, 這代表需要去人為修改, 改完後記得把 #,fuzzy 拿掉.(不管是剛開始的新檔案, 或是之後 msgmerge, 只要有需要人為介入的, po 檔 就會產生 #,fuzzy, 告訴你該去關心一下)
  • 若要翻譯的是此 目錄*.php 和 多個子目錄的*.php, 可用 xgettext --from-code=UTF-8 */*.php *.php
  • xgettext -d NAME, 此 NAME 會等同於 bindtextdomain(), textdomain(), NAME.po, 任何一個沒對應到, 翻譯結果就出不來.
  • _() 不能包括變數($var), 如果 _($var) 有包到變數, 那這行就不會被 xgettext parse 出來.
  • 要判斷要用哪種語系, 判斷法目前想到的有下面幾種:

    • PHP 版

      • $_SERVER["HTTP_ACCEPT_LANGUAGE"]: zh-TW,zh,en-US,en; ...
      • $_SERVER["HTTP_ACCEPT_CHARSET"]: Big5,utf-8;q=0.7,*;q=0.7

    • Javascript 版(可用 document.write() 印出來看看)

      • navigator.browserLanguage # 我測試是 undefined
      • navigator.userLanguage # 我測試是 undefined
      • navigator.language # zh-TW



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-105515-1-1.html 上篇帖子: PHP控制类中方法的访问权限 下篇帖子: Linux下安装、配置PHP环境
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表