[翻譯]Play框架1.2.7版本教程(12) - 國際化和本地化

國際化和本地化

完成了博客引擎後,咱們來考慮額外的一件事:Web應用的國際化和語言的本地化。雖然咱們能夠一開始就作這件事,可是最好仍是先完成該應用的單一語言版本,而後再添加其餘語言的支持。html

國際化和本地化

咱們將分兩步討論,先是國際化,再是本地化。這兩樣都會被重點說起。java

國際化,在編程領域中,指的是移除本地特定的代碼。在Web應用中,基本上是修改模板中特定於語言的交互文本。它還包括修改非文本的數據類型:日期,貨幣和其餘數字。編程

本地化,是打造應用的本地版本。若是應用已經國際化了,就意味着存在一個或多個可選的本地版本。在Web應用中,本地化主要是把交互文本翻譯成特定的語言。這裏的「特定語言」,取決於瀏覽器和應用本身的設置。segmentfault

實際上,二者是同步進行的:你在國際化的同時,每每也是在本地化。api

YABE

咱們這次的起點,是在Play安裝包的samples-and-tests/yabe中的已完成版本。目標是完全國際化應用,而後添加簡體中文的本地版本。(我擅自修改了教程的內容 :D )瀏覽器

如今開始吧。首先打開conf/application.conf,去除註釋或添加一行來支持兩種語言:oracle

# 爲英文,簡體中文本地化
application.langs=en,zh_CN

若是你如今啓動應用,Play命令行會顯示兩個Warning,由於你還沒準備好本地信息文件:app

16:19:04,728 WARN ~ Messages file missing for locale en 
16:19:04,729 WARN ~ Messages file missing for locale zh_CN

UTF-8 信息文件

前面的警告提醒咱們須要把現有的conf/messages文件替換成每一個語言對應一個信息文件:框架

messages.en
messages.zh_CN

在這裏,咱們遇到跟通常在Java中的作法不同的地方。這些文件用的語法跟Java properties文件同樣,但它們不是properties文件,由於它們須要使用UTF-8編碼。而Java properties文件使用的是Latin-1編碼。post

使用UTF-8進行編碼可以給本地化帶來不少的好處。這使得你能夠用純文本記錄下本地化信息。好比,這意味着對於希臘本地化文本,本來須要:

hello.morning = \u0152\u222b\u0152\u00b1\u0152\u00aa\u0152\u2211\u0152\u00ba\u0152\u2260\u0153\u00c5\u0152\u00b1
hello.informal = \u0152\u2265\u0152\u00b5\u0152\u03c0\u0152\u00b1 \u0153\u00c9\u0152\u00f8\u0153\u00d6

如今只需直接使用希臘字母:

hello.morning = καλημέρα 
hello.informal = γεια σου

在本教程剩餘部分,咱們會在上述文件中定義信息,或在HTML模板中使用國際化標記。

簡單的信息

最簡單的狀況是HTML模板中被包含起來的一條文本字符串。舉個例子,在yabe/app/views/main.html模板內的tools列表中:

<ul id="tools"> 
<li> 
<a href="@{Admin.index()}">Log in to write something</a> 
</li> 
</ul>

僅需使用&{'key'}語法,把該文本替換成待查找的信息,就能實現國際化:

<ul id="tools"> 
<li> 
<a href="@{Admin.index()}">&{'views.main.tools.login'}</a> 
</li> 
</ul>

添加對應的行到每一個信息文件,就能實現本地化。在conf/messages.en

views.main.tools.login = Log in to write something

conf/messages.zh_CN

views.main.tools.login = 寫點什麼

具體的內容由你來定;在這個例子中,我使用了一個鍵來標記位置views/main.html#tools

一旦保存了更改,刷新一下,應該能夠看到本來的英文文本變成中文了。這是由於請求中設定了Accept-Languagezh-CN的緣故。

應用模型的本地化

若是登陸進博客的'admin'頁面,你就能看到文章,標籤,評論和用戶的列表。這些頁面是CRUD模塊的功勞。對於每一個頁面,標題和列表頭是與應用的模型,好比JavaBean類和屬性名,聯繫在一塊兒的。

咱們可使用這些模型的名字做爲信息鍵,來國際化CRUD模塊。就跟前面作的同樣:

conf/messages.zh_CN

post = 文章  
Post = 文章
posts = 文章列表
Posts = 文章列表  
comment = 評論
Comment = 評論
comments = 評論列表
Comments = 評論列表
user = 用戶
User = 用戶
users = 用戶列表
Users = 用戶列表

你將注意到那些圓角的紫色導航連接沒有改變:

not changed

它們是在views/admin.html中定義的,經過用&{'...'}把文本包圍起來,你就能把它們國際化:

<a href="@{Posts.list()}">&{'Posts'}</a> 
… 
<a href="@{Tags.list()}">&{'Tags'}</a> 
… 
<a href="@{Comments.list()}">&{'Comments'}</a> 
… 
<a href="@{Users.list()}">&{'Users'}</a>

帶參數的信息

除了字面量字符串,咱們的應用還包括帶有變量的信息,好比posts tagged with Play

對於帶單個參數的字符串,用Java格式化字符串來插入參數:

views.Application.listTagged.title = Posts tagged with %s

接着在模板中,添加這樣的參數:

&{'views.Application.listTagged.title', tag}

當一個信息包括多個參數時,在格式化字符串中添加索引來指定參數順序:

views.Admin.index.welcome = Welcome %1$s, <span>you have written %2$s posts so far</span>

……而後就是這樣:

&{'views.Admin.index.welcome', user, posts.size()}

在這個例子中,咱們想要使用「post」的正確的複數形式,因此也把這個詞當作一個參數:

views.Admin.index.welcome = Welcome %1$s, <span>you have written %2$s %3$s so far</span>

而後在模板中使用pluralize拓展:

&{'views.Admin.index.welcome', user, posts.size(), posts.pluralize(messages.get('post'), messages.get('posts'))}

注意咱們須要使用messages.get來查找對應的單數和複數形式。

對模型層的本地化

對Play模型的本地化就跟對其餘地方的本地化同樣。這個應用使用到了CRUD和Secure模塊,意味着咱們須要本地化play/modules/crud/conf/messagesplay/modules/secure/conf/messages中的用到的信息。

conf/messages.zh_CN:

# play/modules/crud (administration) 
crud.title = 管理面板
crud.home = 主頁
crud.blank = 新增功能 
crud.index.title = 選擇編輯對象
crud.index.objectType = 輸入對象
crud.index.action = 
crud.index.add = 添加
crud.add = &{%s} 添加 
crud.list.title = &{%s} 
crud.list.size = %d &{%s} 
crud.list.totalSize = %d 總計 
crud.pagination.previous = « 上一頁 
crud.pagination.next = 下一頁 » 
crud.pagination.last = 末頁 »» 
crud.pagination.first = «« 首頁 
crud.show.title = &{%s} 編輯 
crud.save = 保存 
crud.saveAndContinue = 保存並繼續編輯
crud.cancel = 取消 
crud.hasErrors = 請更正錯誤 
crud.blank.title = &{%s} 添加
crud.saveAndAddAnother = 保存並新增
crud.delete = &{%s} 刪除 
crud.created = &{%s} 已建立
crud.saved = &{%s} 已保存
crud.deleted = &{%s} 已刪除 
crud.delete.error = 此對象沒法刪除 
crud.search = 搜索 
crud.none = (無) 
crud.help.required = 必填
crud.help.minlength = 至少要有 %d. 
crud.help.maxlength = 最多隻能是 %d. 
crud.help.email = 須要有效郵箱
crud.help.dateformat =  時間格式 YYYY-MM-DD
crud.help.numeric = 須要數值類型 
crud.help.min =  至少須要 %d 
crud.help.future = 在未來 
crud.help.past = 在以前 
crud.help.after = 之上 %s. 
crud.help.before = 之下 %s. 
crud.help.range = 從 %d 到 %d 

# play/modules/secure 
secure.username = 您的郵箱: 
secure.password = 您的密碼: 
secure.signin =  立刻登陸

特殊狀況

當你在本地化一個Web應用時,假如你正在使用一個基於組件的Web應用框架,好比JavaServer Faces,不免會遇到一些難如下手的地方:

  1. 在屬性的值中用到了參數信息
  2. 格式化字符串中的信息
  3. 用做信息的連接

在Play裏,這三點都不是問題。

第一種狀況,你在模板的屬性的值裏用到了參數信息,好比:

<a href="@{Application.show(_post.id)}" title="By Bob">

這是JSF的一個問題,由於一般須要使用XML標籤來完成參數替換,而不能直接在屬性值裏完成。在Play中,你能夠直接這麼寫:

<a href="@{Application.show(_post.id)}" title="&{'views.tags.display.author', _post.author.fullname}">

第二種狀況是在想要使用格式化字符串來排版一個值,好比用參數拼出By Bob on 2009-06-14這樣的日期格式。這又是因爲使用XML標籤來格式化所致使的問題。原本若是能使用一個XML屬性的值來排版,就能解決這個問題。在Play中,因爲傳遞信息參數的語法不同,你不會遇到這樣的問題。你能夠:

<span>&{'views.tags.display.author', _post.author.fullname, comment.postedAt.format('yyyy-MM-dd')}"}</span>

你也能夠這樣寫:

<span>&{'views.tags.display.author', _post.author.fullname, comment.postedAt.format(messages.get('views.dateFormat'))}"}</span>

第三種狀況發生在你想把一個特定信息做爲超連接的時候。在JSF,這是一個問題。由於超連接是一個JSF組件,意味着它的標記不能放在信息文件中。Play,正好相反,容許你在模板中使用原生HTML,因此你能夠把用於URL的參數直接放入帶信息的標記中:

logIn = <a href="%s">Log in</a> to write something

&{'logIn', '/admin'}

咱們應用就曾用<a href="@{Admin.index()}">這樣的語法會讓框架生成基於路由文件的URL。要想在本地化的過程當中處理它,使用:

&{'logIn'}, actionBridge.Admin.index()}

最終成果

來看下咱們給「Yet Another Blog Engine」進行本地化(漢化)的結果。

localization

其實沒有漢化徹底,對吧……(╯▽╰)

相關文章
相關標籤/搜索