同一個 App 在聖保羅和在柏林的表現可能不一樣,而原因從來不會在程式碼審查中出現。後端從 IP 位址猜國家。手機依語系格式化金額。時鐘跟著時區走。Play 商店則顯示帳號所屬國家的目錄與價格。
要測試 App 在不同國家的表現,就要分別控制這幾個訊號,再看看它們不一致時 App 會怎麼做。這篇指南說明怎麼在 Android 上設定每個訊號、能抓到大部分市場 bug 的格式與伺服器端檢查,以及怎麼確認你不在的國家的商店上架頁與價格。
代表「國家」的四個訊號
| 訊號 | 來源 | 會改變什麼 | 測試時怎麼設定 |
|---|---|---|---|
| 網路位置 | 手機連線的 IP 位址 | 後端地區規則、功能開關、CDN 節點、同意流程、內容目錄 | 一支從那個國家連線的手機 |
| 裝置語系 | 系統語言,或 13 以上的個別 App 語言 | 語言、數字、日期與貨幣格式、複數規則、文字方向 | 「設定」,或 cmd locale set-app-locales |
| 時區 | 日期與時間設定 | 時間戳記、「今天」、每日重置、排程通知 | 「設定」,或 cmd alarm set-timezone |
| Play 國家 | Google 帳號的付款資料 | Play 商店目錄、App 是否上架、Play 帳款服務的幣別 | 一個在該國註冊的測試帳號 |
會讀取 TelephonyManager.getSimCountryIso() 的 App,還多了第五個訊號:SIM 卡所屬的國家。這個要用插著當地 SIM 卡的實體手機測試。
訊號不一致時,才抓得到真正的 bug
真實使用者的四個訊號很少全部一致。一位到德國出差的美國工程師,手機是 en-US、Play 帳號在美國、IP 位址在德國,落地後還變成柏林時間。一位在里斯本的巴西學生,用葡萄牙的網路讀 pt-BR 介面。bug 就藏在這些落差裡:
- 後端依 IP 以歐元顯示價格,Play 帳款服務卻依帳號以美元收費。
- App 依 IP 選擇語言,忽略了使用者自己選的語言。
- 「今天」是在伺服器上以 UTC 計算的,所以對聖保羅的使用者來說,每日連續紀錄在晚上 9 點就重置了。
- 依 IP 判斷的同意提示,對一個在本國已經回答過的使用者再次跳出來。
決定哪個訊號驅動哪個功能、把它寫下來,並為每個市場至少測試一種不一致的組合。
在目標國家準備一支手機
網路訊號需要一支真的從那個國家連線的手機。當地辦公室或實驗室裡的實體手機做得到,設定在某個國家的雲手機也做得到。在 Clousd 上,手機可以從你選的國家連線,例如美國、英國、德國、巴西、印尼,以及另外 40 個國家,時區和語言也會跟著設定。完整列表在地區頁面,巴西、德國等市場也有各自的頁面。
測試 App 之前,先確認手機回報的內容:
adb shell getprop persist.sys.timezone adb shell date adb shell cmd locale get-app-locales com.example.app
網路的部分,用手機的瀏覽器打開一個會回顯用戶端國家的網頁,或直接看你自己的後端 log。也要確認你的地理定位服務對這個位址回傳什麼,因為各家資料庫的答案不一定一樣,而重要的是你後端用的那一個。
語系與格式檢查
大部分跟國家有關的 bug,都是格式 bug。讓平台處理格式,再測試你確實交給平台處理了:
- 貨幣。 用
NumberFormat.getCurrencyInstance(locale)格式化,絕對不要自己把符號黏在數字上。以 1234.56 為例,pt-BR 會是R$ 1.234,56,de-DE 會是1.234,56 €:符號位置會移動,分隔符號也會對調。 - 日期與時間。 使用
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)和該語系的一週起始日。12 小時制和 24 小時制都要檢查。 - 複數。 印尼文只有一種複數形式,俄文和波蘭文則有好幾種。用
getQuantityString,而不是對數量寫條件判斷。 - 文字長度。 德文字串可能比英文長 30 %。檢查按鈕、分頁和對話框有沒有被截斷。
- 由右至左。 阿拉伯文和希伯來文的版面是鏡像的。用 start 和 end,而不是 left 和 right。
在翻譯到位之前,虛擬語系(pseudolocale)就能抓到大部分問題。在 debug 建置類型中啟用它,開啟開發人員選項後,在語言設定裡選擇 English (XA) 或 Arabic (XB):
android {
buildTypes {
getByName("debug") {
isPseudoLocalesEnabled = true
}
}
}在 Android 13 以上,你可以只改變單一 App 的語言,不用動到系統語言:
adb shell cmd locale set-app-locales com.example.app --locales pt-BR adb shell cmd locale set-app-locales com.example.app --locales de-DE
App 必須透過 localeConfig 宣告或 AppCompat 支援個別 App 語言,變更才會生效。如果要測試和網路不一致的時區,也就是上面出差的情境,可以直接用 adb shell cmd alarm set-timezone America/Sao_Paulo 設定。
伺服器端的行為
伺服器依 IP 位址決定的每一件事,都需要從那個國家測試:
- 依國家設定的功能開關與遠端設定。
- 各市場不同的結帳選項與付款方式。
- 同意與隱私流程:歐盟與英國的 GDPR、巴西的 LGPD、美國各州的隱私法。
- 內容目錄、年齡分級與法律聲明。
- CDN 節點,以及使用者實際感受到的延遲。
在測試版建置中,把後端每個請求判定的國家記錄下來。測試失敗時,第一個要問的是:伺服器以為這支手機在哪個國家?
其他國家的商店上架頁與價格
Play 商店跟著帳號走,而不是跟著網路走。每個 Google 帳號都有一個由付款資料決定的 Play 國家,使用者一年只能變更一次。一支在德國、登入美國帳號的手機,看到的仍然是美國商店:美國的上架頁、美國的上架範圍和美國的價格。改變手機語言,改變的是上架頁的語言,而不是國家。
要確認某個市場的使用者看到什麼:
- 上架頁文字與圖片。 Play 管理中心裡的自訂商店資訊可以針對特定國家,主要商店資訊則有各語言的翻譯。在 Play 管理中心逐一預覽。
- 上架範圍。 你在 Play 管理中心選擇的國家與地區,決定了 App 能在哪裡安裝。透過內部或封閉測試群組,請一位帳號屬於該國的測試人員確認。
- 價格。 Play 帳款服務會透過商品方案詳細資料中的
getFormattedPrice(),回傳已經為買家換算並格式化好的價格。直接顯示這個字串,絕對不要顯示你自己算的價格,並用授權測試人員測試購買流程。
想更全面了解推薦內容、價格與商店頁面如何因市場而變,請看怎麼從其他國家看自己的內容。
每個國家的檢查清單
- App 以裝置或 App 語系的語言啟動,而不是 IP 暗示的語言。
- 價格、數字、日期與時間都使用當地格式。
- 長字串放得下,由右至左的市場正確鏡像。
- 每日重置、排程通知、「今天」與「昨天」都依當地時區計算。
- 該國的伺服器端行為:功能開關、同意流程、目錄、結帳選項。
- 至少一種不一致的組合:當地網路搭外國語系,或當地語系搭外國帳號。
- 商店上架頁、上架範圍與 Play 帳款服務的價格,用該國的測試帳號確認過。
- 每個市場的每個關鍵畫面都截圖,和版本一起保存,方便比較。
也要在使用者實際用的 Android 版本上跑這份清單;在不同 Android 版本上測試 App 涵蓋了個別 App 語言與其他各版本之間的差異。
先測哪些國家
先從帶來營收、或即將帶來營收的市場開始。接著,為每一種還沒涵蓋到的格式類型各加一個市場:一個以逗號作小數點的市場,例如德國或巴西;一個由右至左的市場;以及一個使用非拉丁文字的市場。如果你正在東南亞擴張,印尼能帶來龐大的受眾,以及它自己的語言與數字格式。


