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

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

絮叨絮叨:好久不来写了,竟然支持markdown 了。 我也是在项目里的wiki 里干刚接触了一些, 来这里也试试。然后悲催的发现,mac 电脑在markdown下直接上传图片有bug @2015-08-19 20:28:13。一会试一下链接版的吧。
我们的37度手环一不小心要卖到国外去了,自然要支持多国家多语言啦。 等卖到阿拉伯世界的时候,我会再补充RTL(Right To Left)相关的内容。

本文仅涉及安卓(Android)客户端的实现, 服务器后台的部分没有介绍。 主要介绍了多语言中文字、图片的使用, 以及如何修改下拉菜单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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-20 18:28:29

我在写多语言支持时用到的东西的相关文章

一个轻客户端,多语言支持,去中心化,自动负载,可扩展的实时数据写服务的实现方案讨论

背景 背景是设计一个实时数据接入的模块,负责接收客户端的实时数据写入(如日志流,点击流),数据支持直接下沉到HBase上(后续提供HBase上的查询),或先持久化到Kafka里,方便后续进行一些计算和处理,再下沉到文件系统或做别的输出. 在设计中,对于客户端和服务端有这么些目标. 客户端需要支持多语言(Java,C++),做得尽量轻量级,只要连上服务端的ip:port,以RPC的形式调用简单的write就可以把数据写出去.客户端不承担任何逻辑的处理,服务端的负载均衡对客户端是透明的. 服务端想要

PHP Laravel 本地化语言支持

That`s it. 我发现在网上Laravel的学习资料实在是太少了.好多东西需要自己去弄.去理解. 我的方法还有一个,就是去github上面下载老外写的Laravel网站,然后拿下来自己运行,分析代码,然后找出其中的出彩的地方.恩,很不错的方法.今天让我找到了一个好东西,就是Laravel 本地化语言的功能. 所谓本地化语言,就是说在不同的的国家可能使用不同的语言.那么如果没有适应各个语言的程序,也就意味着程序需要重写.现在Laravel提供了一个方便的功能,本地化语言支持. 好了,下面让我

【转】解析JDK 7的动态类型语言支持

http://www.infoq.com/cn/articles/jdk-dynamically-typed-language Java虚拟机的字节码指令集的数量自从Sun公司的第一款Java虚拟机问世至JDK 7来临之前的十余年时间里,一直没有发生任何变化[1].随着JDK 7的发布,字节码指令集终于迎来了第一位新成员——invokedynamic指令.这条新增加的指令是JDK 7实现“动态类型语言(Dynamically Typed Language)”支持而进行的改进之一,也是为JDK 8

DDD开发框架ABP之本地化/多语言支持

本地化(Localization)也就是多语言功能,借此用户能够选择他的母语或熟悉的语言来使用系统,这显然非常有利于软件系统推向国际化.一个应用程序的UI界面至少有一种语言,DDD开发框架ABP就提供了一个弹性的多语言框架,可以简化我们在多语言方面的开发时间.利用ABP完整实现多语言只需要简单地完成三个步骤:建立资源.配置资源以及使用资源. 一.建立资源 本地化的内容主要是文本字符串,ABP提供三种方式存储本地化资源的方式,分别是ASP.NET自带的资源文件.XML文件以及自定义的资源获取方式.

在VC工程中添加多语言支持[转]

随着贸易国际化,在软件开发过程中,常会碰到需在现有中文版软件加入多语言支持的情况.由于不同语言版本间的差别通常仅是软件操作界面的不同,为实现多语言支持,使用纯资源DLL是一个不错的解决之道.所谓纯资源DLL是指只包含资源的DLL,譬如:快捷键.对话框.字符串.菜单.工具条.位图.图标.版本信息等等. 具体做法是:利用VC可视化编辑环境为每种语言制作一套资源ID一一对应的资源集并编译生成DLL文件.应用程序初始化时按预设的语言设置选择合适的资源DLL调入,使用资源时依据资源ID进行访问,这样即可实

IOS写一个可以支持全屏的WebView

这样来写布局 一个TitleView作为顶部搜索栏: @implementation TitleView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code [self initTilte]; } return self; } -(void)initTilte{ UITextField* field = [[UITextField al

MVC4多语言支持

第一步 建立资源文件 为WEB项目添加Resource文件夹,然后在Resource文件夹下添加两个resx文件en-US.resx和zh-CN.resx文件. 使用Resgen.exe将resx转为resource文件(Resgen.exe可以放到windows/system32或windows/syswow64下),cmd运行下列语句: resgen D:\WORKSPACE\Locale\Locale\Resource\en-US.resx D:\WORKSPACE\Locale\Loca

Android 原生应用开发得到Go语言支持

今天的主要内容为Android 原生应用开发得到Go 语言支持,那么我们首先简单看下GO是什么呢? Go是Google开发的一种编译型,並發型,并具有垃圾回收功能的编程语言. Google工程师和独立开发人员提出了几份不同的提案,旨在让Go语言支持开发原生的Android应用.这项工作无法让Go语言编写的应用使用Android NDK的全部接口,但有可能使用其中的一个子集. David Crawshaw是Google的工程师,他写了一份提案,旨在让Go语言部分支持编写Android应用.根据他的

thinkPHP的多语言支持如何配置和部署

框架底层语言包位于:ThinkPHP/Lang/zh-cn.php 可以参考如何编写语言文件 第一步:项目目录下的配置文件中配置多语言支持的相关选项 以我的路径为例是Application\Common\Conf\config.php 配置内容如下:   'LANG_SWITCH_ON'     =>     true,    //开启语言包功能            'LANG_AUTO_DETECT'     =>     true, // 自动侦测语言    'DEFAULT_LANG'