我在寫多語言支持時用到的東西
我在寫多語言支持時用到的東西
絮叨絮叨:好久不來寫了,居然支持markdown 了。 我也是在項目裏的wiki 裏幹剛接觸了一些, 來這裏也試試。然後悲催的發現,mac 電腦在markdown下直接上傳圖片有bug @2015-08-19 20:28:13。
一會試一下鏈接版的吧。
我們的37度手環一不小心要賣到國外去了,自然要支持多國家多語言啦。 等賣到阿拉伯世界的時候,我會再補充RTL(Right To Left)相關的內容。
本文僅涉及安卓(Android)client的實現。 server後臺的部分沒有介紹。 主要介紹了多語言中文字、圖片的使用, 以及怎樣改動下拉菜單Spinner。在處理過程中還介紹了經常使用的shell 命令,awk命令,高效工作,高效生活。
安卓(Android)開發本身對多語言有著不錯的支持,尤其在新版Android Studio 中還直接增加了多語言編輯器。
處理多語言時是絕對的神器。
官網的支持[Support Multi Language][2]
字符翻譯
當然要使用神器 studio中的多語言editor
圖1 編輯器打開位置
圖2 編輯器界面
圖3 文件夾結構
帶文字的圖片處理
和文字的原理一樣。分別建立相應語言的圖片文件夾
比如相應drawable-xhdpi 不同語言/地區的文件夾是
drawable-ko-xhdpi
drawable-zh-xhdpi
圖4 圖片多語言文件夾
真正的多國功能——支持多國短信驗證碼
準備1 多國區號
多國區號[Country Code][1]
拿來是一個大表,兩百多行。整理一下存成markdown 文件,方便以後查看和編輯
一般拷貝出來是制表符 \t 切割的。 我是用vim 一通替換,把數量不等空格 和\t 統統換成 | 。 詳細vim的操作命令例如以下:
#在vim 中多次運行,把全部的\t 換成 多個空格
:%s/\t/ |/g
#然後把多個空格 換成|
:%s/ */|/g
這樣形成了例如以下格式
$ head CountryNumber.md
#Country Number table
Countries and Regions|國家或地區|時差|電話代碼|國際域名縮寫
------------------------|-----------|-----------|-------|-----
Angola|安哥拉|-7|244|AO
Afghanistan|阿富汗|0|93|AF
Albania|阿爾巴尼亞|-7|355|AL
Countries and Regions | 國家或地區 | 時差 | 電話代碼 | 國際域名縮寫 |
---|---|---|---|---|
Angola | 安哥拉 | -7 | 244 | AO |
Afghanistan | 阿富汗 | 0 | 93 | AF |
Albania | 阿爾巴尼亞 | -7 | 355 | AL |
準備2 country code 的string-array
分別在各個語言/地區資源文件夾下存儲成string-array。這裏處理使用awk。分別獲取country name 和相應的country code。
詳細shell 命令例如以下
$ cat CountryNumber.md | awk -F‘|‘ ‘{print "<item>"$2"|"$4"</item>"}‘ > cn.txt
$ cat CountryNumber.md | awk -F‘|‘ ‘{print "<item>"$1"|"$4"</item>"}‘ > en.txt
<string-array name="country_code">
<item>安哥拉|244</item>
<item>阿富汗|93</item>
<item>阿爾巴尼亞|355</item>
</string-array>
<string-array name="country_code">
<item>Angola|244</item>
<item>Afghanistan|93</item>
<item>Albania|355</item>
</string-array>
JAVA代碼解析,並排序
既然是用| 切割的。 接下來就是代碼解析一下, 並在展示之前排序
public static ArrayList<Country> getCountryCode(Context ctx) {
ArrayList<Country> retList = new ArrayList<>();
String[] array = ctx.getResources().getStringArray(R.array.country_code);
for (String item : array) {
String[] data = item.split("\\|");
Country country = new Country();
country.name = data[0];
country.code = data[1];
retList.add(country);
}
Collections.sort(retList);
return retList;
}
排序須要class Country 實現排序接口comparable
當系統語言使用中文時,使用Collator。能夠自己主動按漢字的拼音的排序。
public class Country implements Comparable<Country> {
public String name;
public String code;
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
return buffer.append(name).append(", ")
.append(code).toString();
}
@Override
public int compareTo(Country another) {
if (another == null) {
return -1;
}
Collator cmp = Collator.getInstance(Locale.getDefault());
return cmp.compare(this.name, another.name);
}
}
自己定義 spinner 下拉選擇country code
先看一下實現效果,兩種樣式的spinner
圖 spinner 截圖
沒什麽高科技,就是讓spinner 按自己的意思來顯示。 在不同的地方使用了兩種。 靈活運用不就是攻城獅要幹的事情麽。
spinner 的界面改動主要是兩部分:
一個是未展開狀態,在getView()中改動,能夠更改三角圖片,控制顯示位置等;
還有一個是展開狀態——在getDropdownView() 中改動, 控制展開後的顯示內容。
CountrySpinnerAdapter 的實現
public class CountrySpinnerAdapter extends ArrayAdapter<Country> {
private Context context;
private ArrayList<Country> mCountryList;
private Spinner mSpinner;
private boolean mIsFamilySpinner;
public CountrySpinnerAdapter(Context context, Spinner spinner, ArrayList<Country> countryList, boolean isFamilySpinner) {
super(context, R.layout.country_spinner_item, countryList);
this.context = context;
mCountryList = countryList;
mSpinner = spinner;
this.mIsFamilySpinner = isFamilySpinner;
}
public CountrySpinnerAdapter(Context context, Spinner spinner, ArrayList<Country> countryList) {
this(context, spinner, countryList, false);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(getContext(), mIsFamilySpinner ? R.layout.country_spinner_layout_family : R.layout.country_spinner_layout, null);
}
Country country = mCountryList.get(position);
TextView name = (TextView) convertView.findViewById(R.id.country_name);
TextView code = (TextView) convertView.findViewById(R.id.country_code);
name.setText(country.name);
code.setText("+" + country.code);
if (mSpinner.getSelectedItemPosition() == position) {
convertView.setSelected(true);
} else {
convertView.setSelected(false);
}
return convertView;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(getContext(), mIsFamilySpinner ? R.layout.country_spinner_item_family : R.layout.country_spinner_item, null);
}
Country country = (Country) mSpinner.getSelectedItem();
if (mIsFamilySpinner) {
TextView code = (TextView) convertView.findViewById(R.id.country_code);
code.setText("+" + country.code);
} else {
TextView name = (TextView) convertView.findViewById(R.id.country_name);
TextView code = (TextView) convertView.findViewById(R.id.country_code);
name.setText(country.name);
code.setText("+" + country.code);
}
if (mSpinner.getSelectedItemPosition() == position) {
convertView.setSelected(true);
} else {
convertView.setSelected(false);
}
return convertView;
}
}
分別使用不用的 layout 來控制:
layout/country_spinner_item.xml
一個水平layout 中 包括
兩個textview 分別顯示name 和code
一個ImageView, ImageView 用來顯示下拉的三角
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:background="@drawable/family_spinner_bg"
android:orientation="horizontal">
<TextView
android:id="@+id/country_name"
android:layout_marginLeft="8dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="@string/family_dialog_phone_number"
android:textColor="@color/family_dialog_message"
android:textSize="18sp" />
<TextView
android:id="@+id/country_code"
android:layout_marginRight="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/family_dialog_message"
android:textSize="18sp" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/country_spinner_arrow" />
</LinearLayout>
layout/country_spinner_layout.xml
一個水平layout 中 包括
兩個textview 分別顯示name 和code
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="25dp"
android:background="@drawable/family_spinner_back"
android:gravity="center_vertical">
<TextView
android:id="@+id/country_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_weight="1"
android:duplicateParentState="false"
android:ellipsize="end"
android:singleLine="true"
android:text="@string/family_dialog_phone_number"
android:textColor="@color/family_spinner_text"
android:textSize="18sp" />
<TextView
android:id="@+id/country_code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:duplicateParentState="false"
android:text="@string/family_dialog_phone_number"
android:textColor="@color/family_spinner_text"
android:textSize="18sp" />
</LinearLayout>
能看到這裏,說明也是緣分。廣告一下。有緣人看過來:這裏上有70後靠譜大叔CXO,下有90後蘿莉鮮肉,前有各種博士搞定算法硬件,後有臉皮厚猥瑣男拿下銷售。
如今人手緊缺,安卓開發。IOS 開發,UI/UX。產品經理都須要人,活真的要幹只是來了。希望自我驅動力強,能夠平衡風險收益的同學歡迎來勾搭。
鄙人37度手環安卓開發,扣扣:84365252。
[1]: https://countrycode.org/ country code
[2]: http://developer.android.com/training/basics/supporting-devices/languages.html Support Multi Languages
我在寫多語言支持時用到的東西