1. 程式人生 > >我在寫多語言支持時用到的東西

我在寫多語言支持時用到的東西

不同語言 ttext hdp 漢字 經理 getc 下拉 rtl 真的

我在寫多語言支持時用到的東西

絮叨絮叨:好久不來寫了,居然支持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

我在寫多語言支持時用到的東西