• 我在写多语言支持时用到的东西


    我在写多语言支持时用到的东西

    絮叨絮叨:好久不来写了,居然支持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 文件,方便以后查看和编辑
    一般拷贝出来是制表符 切割的。 我是用vim 一通替换,把数量不等空格 和 统统换成 | 。 详细vim的操作命令例如以下:

    #在vim 中多次运行,把全部的	 换成 多个空格
    :%s/	/  |/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 截图

    没什么高科技,就是让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

  • 相关阅读:
    inode满处理
    power shell 脚本了解
    免密脚本带端口
    linux文件 特殊权限的使用
    linux批量配置ip
    编译安装常用包+阿里镜像源-常用资源-系统-下载-科莱软件下载-docker仓库包-安全圈-杏雨梨云-图形界面安装-docker私有双仓库-阿里源报错处理-centos7目录大小
    expect免互交 常用编辑文本
    vim 插件 -- taglist
    vim 插件 -- ctags
    vim 插件 -- omnicppcomplete
  • 原文地址:https://www.cnblogs.com/yfceshi/p/7260472.html
Copyright © 2020-2023  润新知