首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android开发笔记(八十三)多语言支持

Android开发笔记(八十三)多语言支持

作者头像
aqi00
发布于 2019-01-18 06:37:28
发布于 2019-01-18 06:37:28
1.1K00
代码可运行
举报
文章被收录于专栏:老欧说安卓老欧说安卓
运行总次数:0
代码可运行

汉字转拼音

app中有许多场景要对汉字排序,例如通讯录姓名、商品名称、城市名称等等,这些汉字词汇通常是按照拼音排序,所以产生了把汉字转换为拼音的需求。

Android自带库

Android自带的联系人应用,就支持对联系人按照姓名排序,内置汉字转拼音的源码位于路径“packages\providers\ContactsProvider\src\com\android\providers\contacts\HanziToPinyin.java”。该工具类早期的源码,直接把字符集合写在java文件中,这种做法在4.2以上版本不能正常工作。4.2以上的工具源码改为调用底层的jni接口,具体说来,便是HanziToPinyin.java引用了核心库libcore.icu的Transliterator类,Transliterator内部有提供数个native方法。 不管是HanziToPinyin类还是Transliterator类,都属于系统源码,不属于sdk源码,也就是说,app开发无法直接调用这两个类的方法。只能是把这两个类的java文件直接复制到app工程中,才能正常调用其中的api。同时注意,Transliterator.java必须放在名称是libcore.icu的包路径下,因为该类引用了jni接口,而jni接口要求包名、类名、方法名都保持一致才能正常运行,jni的详细说明参见《Android开发笔记(六十九)JNI实战》。 下面是HanziToPinyin.java的源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import android.text.TextUtils;
import android.util.Log;

import java.util.ArrayList;

import libcore.icu.Transliterator;

public class HanziToPinyin {
    private static final String TAG = "HanziToPinyin";

    private static HanziToPinyin sInstance;
    private Transliterator mPinyinTransliterator;
    private Transliterator mAsciiTransliterator;

    public static class Token {
        public static final String SEPARATOR = " ";
        public static final int LATIN = 1;
        public static final int PINYIN = 2;
        public static final int UNKNOWN = 3;

        public Token() {
        }

        public Token(int type, String source, String target) {
            this.type = type;
            this.source = source;
            this.target = target;
        }

        public int type;
        public String source;
        public String target;
    }

    private HanziToPinyin() {
        try {
        	mPinyinTransliterator = new Transliterator("Han-Latin/Names; Latin-Ascii; Any-Upper");
        	mAsciiTransliterator = new Transliterator("Latin-Ascii");
        } catch (RuntimeException e) {
            Log.w(TAG, "Han-Latin/Names transliterator data is missing," + " HanziToPinyin is disabled");
        }
    }

    public boolean hasChineseTransliterator() {
        return mPinyinTransliterator != null;
    }

    public static HanziToPinyin getInstance() {
        synchronized (HanziToPinyin.class) {
            if (sInstance == null) {
                sInstance = new HanziToPinyin();
            }
            return sInstance;
        }
    }

    private void tokenize(char character, Token token) {
        token.source = Character.toString(character);

        // ASCII
        if (character < 128) {
            token.type = Token.LATIN;
            token.target = token.source;
            return;
        }

        // Extended Latin. Transcode these to ASCII equivalents
        if (character < 0x250 || (0x1e00 <= character && character < 0x1eff)) {
            token.type = Token.LATIN;
            token.target = mAsciiTransliterator == null ? token.source :
                mAsciiTransliterator.transliterate(token.source);
            return;
        }

        token.type = Token.PINYIN;
        token.target = mPinyinTransliterator.transliterate(token.source);
        if (TextUtils.isEmpty(token.target) ||
            TextUtils.equals(token.source, token.target)) {
            token.type = Token.UNKNOWN;
            token.target = token.source;
        }
    }

    public String transliterate(final String input) {
        if (!hasChineseTransliterator() || TextUtils.isEmpty(input)) {
            return null;
        }
        return mPinyinTransliterator.transliterate(input);
    }

    public ArrayList<Token> getTokens(final String input) {
        ArrayList<Token> tokens = new ArrayList<Token>();
        if (!hasChineseTransliterator() || TextUtils.isEmpty(input)) {
            return tokens;
        }

        final int inputLength = input.length();
        final StringBuilder sb = new StringBuilder();
        int tokenType = Token.LATIN;
        Token token = new Token();

        for (int i = 0; i < inputLength; i++) {
            final char character = input.charAt(i);
            if (Character.isSpaceChar(character)) {
                if (sb.length() > 0) {
                    addToken(sb, tokens, tokenType);
                }
            } else {
                tokenize(character, token);
                if (token.type == Token.PINYIN) {
                    if (sb.length() > 0) {
                        addToken(sb, tokens, tokenType);
                    }
                    tokens.add(token);
                    token = new Token();
                } else {
                    if (tokenType != token.type && sb.length() > 0) {
                        addToken(sb, tokens, tokenType);
                    }
                    sb.append(token.target);
                }
                tokenType = token.type;
            }
        }
        if (sb.length() > 0) {
            addToken(sb, tokens, tokenType);
        }
        return tokens;
    }

    private void addToken(
            final StringBuilder sb, final ArrayList<Token> tokens, final int tokenType) {
        String str = sb.toString();
        tokens.add(new Token(tokenType, str, str));
        sb.setLength(0);
    }
}

下面是Transliterator.java的源码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package libcore.icu;
/**
 * Exposes icu4c's Transliterator.
 */
public final class Transliterator {
  private long peer;
  /**
   * Creates a new Transliterator for the given id.
   */
  public Transliterator(String id) {
    peer = create(id);
  }
  @Override protected synchronized void finalize() throws Throwable {
    try {
      destroy(peer);
      peer = 0;
    } finally {
      super.finalize();
    }
  }
  /**
   * Returns the ids of all known transliterators.
   */
  public static native String[] getAvailableIDs();
  /**
   * Transliterates the specified string.
   */
  public String transliterate(String s) {
    return transliterate(peer, s);
  }
  private static native long create(String id);
  private static native void destroy(long peer);
  private static native String transliterate(long peer, String s);
}

下面是调用HanziToPinyin的代码例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
String pinyin = HanziToPinyin.getInstance().transliterate("我爱你中国");

pinyin4j

pinyin4j是java版本的拼音库,可直接拿到android上使用。pinyin4j与Android自带库相比,多出的功能有: 1、支持展示多音字的不同拼音; 2、支持显示汉字拼音的四个声调; pinyin4j中常用的就是两个类,一个类HanyuPinyinOutputFormat是用来设置拼音格式的,另一个类PinyinHelper是用来进行转换操作的。 下面是HanyuPinyinOutputFormat的常用方法说明: setCaseType : 设置拼音的大小写。HanyuPinyinCaseType.UPPERCASE表示大写,HanyuPinyinCaseType.LOWERCASE表示小写。 setToneType : 设置拼音的声调形式。HanyuPinyinToneType.WITHOUT_TONE表示不标声调,HanyuPinyinToneType.WITH_TONE_NUMBER表示在拼音末尾标注数字1-4表示四个声调,HanyuPinyinToneType.WITH_TONE_MARK表示在拼音上方标注四个声调的符号。 setVCharType : 设置特殊拼音ü的的显示格式。HanyuPinyinVCharType.WITH_V表示ü显示为字符v,HanyuPinyinVCharType.WITH_U_AND_COLON表示ü显示为字符u:,HanyuPinyinVCharType.WITH_U_UNICODE表示ü显示为字符ü。 注意:当声调形式设置为符号声调时,setVCharType只能选择HanyuPinyinVCharType.WITH_U_UNICODE,否则运行时会报错“net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination: tone marks cannot be added to v or u:”。 下面是PinyinHelper的常用方法说明: toHanyuPinyinStringArray : 转为汉字拼音。中国大陆使用 toTongyongPinyinStringArray : 转为通用拼音。中国台湾使用 toWadeGilesPinyinStringArray : 转为威妥玛拼音。 toMPS2PinyinStringArray : 转为注音符号拼音。 toYalePinyinStringArray : 转为耶魯拼音。 toGwoyeuRomatzyhStringArray : 转为国语罗马字。 下面是pinyin4j的一个使用例子代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

public class pinyin4j {

	public static String makeStringByStringSet(Set<String> stringSet) {
		StringBuilder str = new StringBuilder();
		int i = 0;
		for (String s : stringSet) {
			if (i == stringSet.size() - 1) {
				str.append(s);
			} else {
				str.append(s + ",");
			}
			i++;
		}
		return str.toString().toLowerCase(Locale.getDefault());
	}

	public static Set<String> getPinyin(String src) {
		if (src != null && !src.trim().equalsIgnoreCase("")) {
			char[] srcChar;
			srcChar = src.toCharArray();
			// 汉语拼音格式输出类
			HanyuPinyinOutputFormat hanYuPinOutputFormat = new HanyuPinyinOutputFormat();

			// 输出设置,大小写,音标方式等
			hanYuPinOutputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
			hanYuPinOutputFormat.setToneType(HanyuPinyinToneType.WITH_TONE_MARK);
			hanYuPinOutputFormat.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);

			String[][] temp = new String[src.length()][];
			for (int i = 0; i < srcChar.length; i++) {
				char c = srcChar[i];
				// 是中文或者a-z或者A-Z转换拼音(我的需求,是保留中文或者a-z或者A-Z)
				if (String.valueOf(c).matches("[\\u4E00-\\u9FA5]+")) {
					try {
						temp[i] = PinyinHelper.toHanyuPinyinStringArray(
								srcChar[i], hanYuPinOutputFormat);
					} catch (BadHanyuPinyinOutputFormatCombination e) {
						e.printStackTrace();
					}
				} else if (((int) c >= 65 && (int) c <= 90)
						|| ((int) c >= 97 && (int) c <= 122)) {
					temp[i] = new String[] { String.valueOf(srcChar[i]) };
				} else {
					temp[i] = new String[] { "" };
				}
			}
			String[] pingyinArray = Exchange(temp);
			Set<String> pinyinSet = new HashSet<String>();
			for (int i = 0; i < pingyinArray.length; i++) {
				pinyinSet.add(pingyinArray[i]);
			}
			return pinyinSet;
		}
		return null;
	}

	public static String[] Exchange(String[][] strJaggedArray) {
		String[][] temp = DoExchange(strJaggedArray);
		return temp[0];
	}

	private static String[][] DoExchange(String[][] strJaggedArray) {
		int len = strJaggedArray.length;
		if (len >= 2) {
			int len1 = strJaggedArray[0].length;
			int len2 = strJaggedArray[1].length;
			int newlen = len1 * len2;
			String[] temp = new String[newlen];
			int Index = 0;
			for (int i = 0; i < len1; i++) {
				for (int j = 0; j < len2; j++) {
					temp[Index] = strJaggedArray[0][i] + strJaggedArray[1][j];
					Index++;
				}
			}
			String[][] newArray = new String[len - 1][];
			for (int i = 2; i < len; i++) {
				newArray[i - 1] = strJaggedArray[i];
			}
			newArray[0] = temp;
			return DoExchange(newArray);
		} else {
			return strJaggedArray;
		}
	}
	
	public static String getPinyinFull(String hanzi) {
		return makeStringByStringSet(getPinyin(hanzi));
	}

}

下面是Android自带库与pinyin4j转换汉字拼音的截图:

国际语言版本

如同很多windows桌面软件一样,Android也支持将应用发布为多语言版本,即随着手机系统设置的语言变化,app也随之显示对应的语言文本。Android支持对app的字符串和图片分别做国际化处理,字符串国际化只要在res下新建对应语言的values目录就好,比如英文环境的目录命名为“values-en”,中文环境的目录命名为“values-zh”。ADT新建Android项目时,会在res目下自动创建默认环境的values目录,如果某个语言环境没有在项目中定义配置,那么也会使用values下的资源。 Android的图片国际化同理,即在res下新建drawable-zh目录,存放中文环境下的图片;新建drawable-en目录,存放英文环境下的图片。不同分辨率的图片也可以按此规则处理,例如drawable-zh-hdpi表示中文环境下高分辨率的图片目录。 下面是Android多国语言的目录命名列表: 中文(中国大陆):values-zh-rCN 中文(中国台湾):values-zh-rTW 中文(中国香港):values-zh-rHK 英文(美国):values-en-rUS 英文(英国):values-en-rGB 英文(澳大利亚):values-en-rAU 英文(加拿大):values-en-rCA 英文(爱尔兰):values-en-rIE 英文(印度):values-en-rIN 英文(新西兰):values-en-rNZ 英文(新加坡):values-en-rSG 英文(南非):values-en-rZA 阿拉伯文(埃及):values-ar-rEG 阿拉伯文(以色列):values-ar-rIL 保加利亚文:  values-bg-rBG 加泰罗尼亚文(西班牙):values-ca-rES 捷克文:values-cs-rCZ 丹麦文:values-da-rDK 德文(奥地利):values-de-rAT 德文(瑞士):values-de-rCH 德文(德国):values-de-rDE 德文(列支敦士登):values-de-rLI 希腊文:values-el-rGR 西班牙文(西班牙):values-es-rES 西班牙文(美国):values-es-rUS 芬兰文:values-fi-rFI 法文(比利时):values-fr-rBE 法文(加拿大):values-fr-rCA 法文(瑞士):values-fr-rCH 法文(法国):values-fr-rFR 希伯来文(以色列):values-iw-rIL 印地文(印度):values-hi-rIN 克罗地亚文:values-hr-rHR 匈牙利文:values-hu-rHU 印度尼西亚文:values-in-rID 意大利文(瑞士):values-it-rCH 意大利文(意大利):values-it-rIT 日文:values-ja-rJP 韩文:values-ko-rKR 立陶宛文:valueslt-rLT 拉脱维亚文:values-lv-rLV 博克马尔文(挪威):values-nb-rNO 荷兰文(比利时):values-nl-BE 荷兰文(荷兰):values-nl-rNL 波兰文:values-pl-rPL 葡萄牙文(巴西):values-pt-rBR 葡萄牙文(葡萄牙):values-pt-rPT 罗马尼亚文:values-ro-rRO 俄文:values-ru-rRU 斯洛伐克文:values-sk-rSK 斯洛文尼亚文:values-sl-rSI 塞尔维亚文:values-sr-rRS 瑞典文:values-sv-rSE 泰文(泰国):values-th-rTH 塔加洛文(菲律宾):values-tl-rPH 土耳其文:values--r-rTR 乌克兰文:values-uk-rUA 越南文:values-vi-rVN 点击下载本文用到的多语言支持的工程代码 点此查看Android开发笔记的完整目录

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016年03月21日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Linux开启Docker远程访问并设置安全访问(证书密钥),附一份小白一键设置脚本哦!
找到 Service节点,修改ExecStart属性,增加 -H tcp://0.0.0.0:2375
JanYork_简昀
2023/02/02
4.8K0
Linux开启Docker远程访问并设置安全访问(证书密钥),附一份小白一键设置脚本哦!
go-https的简单实现
X.509 Certificate Signing Request (CSR) Management.
fnatic
2022/07/22
24.7K0
Docker开启远程安全访问
找到 Service 节点,修改 ExecStart 属性,增加 -H tcp://0.0.0.0:2375
niceyoo
2020/07/09
10K0
TLS加密远程连接Docker
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
程序员欣宸
2019/09/18
2.2K0
TLS加密远程连接Docker
centos7/6.9 docker-ce-17/1.7.1使用证书登陆(openssl tls)
出现 Error response from daemon: client is newer than server (client API version: 1.24, server API version: 1.19)
全栈程序员站长
2021/05/19
3010
Docker暴露2375端口,引起安全漏洞
前几天有小伙伴发现Docker暴露出2375端口,引起了安全漏洞。我现在给大家介绍整个事情的来龙去脉,并告诉小伙伴们,怎么修复这个漏洞。
全栈程序员站长
2022/09/05
3.6K0
Docker暴露2375端口,引起安全漏洞
Docker 远程连接 -- dockerd 命令详解
配置 TLS 实现安全的 Docker 远程连接。 GitHub:https://github.com/khs1994-docker/dockerd-tls 本机:macOS 远程机:使用 VirtualBox 虚拟 CoreOS (IP 192.168.57.110) 目标:能在 macOS 远程操作 CoreOS。(注意不是 SSH 远程登录)。dockerd 命令仅能在 Linux 下使用。 官方文档:https://docs.docker.com/edge/engine/reference/comm
康怀帅
2018/02/28
24.7K2
Docker启用TLS进行安全配置
之前开启了docker的2375 Remote API,接到公司安全部门的要求,需要启用授权,翻了下官方文档
JadePeng
2019/08/14
9340
docker安装篇,第二篇 在Ubuntu18.04上开启RESTful API接口,HTTP与HTTPS接口访问
https://docs.docker.com/install/linux/linux-postinstall/#next-steps
cn華少
2018/08/31
1.6K0
docker安装篇,第二篇 在Ubuntu18.04上开启RESTful API接口,HTTP与HTTPS接口访问
Docker服务开放了这个端口,服务器分分钟变肉机!
Docker为了实现集群管理,提供了远程管理的端口。Docker Daemon作为守护进程运行在后台,可以执行发送到管理端口上的Docker命令。
macrozheng
2020/08/13
1.6K0
在Ubuntu16.10上开启docker17.03.0-ce的https认证
$ openssl genrsa -aes256 -out ca-key.pem 4096
cn華少
2018/09/11
3800
Docker开启TLS和CA认证
前言:Docker直接开启2375端口是不安全的,别人只要连上之后就可以任意操作,下面是开启Docker的TLS和CA认证方法,并使用Jenkins和Portainer连接。 一、生成证书 查看服务器主机名 hostname [image-20210826174816658] 安装生成证书软件 yum install -y openssl [image-20210827003357785] 编写一键启动脚本 auto-generate-docker-tls-ca.sh # !/bin/bash # 一键生
小强崽
2022/05/20
1.7K0
SSL与TLS协议原理与证书签名多种生成方式实践指南
原文地址: SSL与TLS协议原理与证书签名多种生成方式实践指南 (https://mp.weixin.qq.com/s/g-X8UPNwIkuR_Qd2MDvVQw)
全栈工程师修炼指南
2022/09/29
1.8K0
SSL与TLS协议原理与证书签名多种生成方式实践指南
04. Idea集成Docker
上一节中,我们介绍了Dockerfile的方式构建自己的镜像。但是在实际开发过程中,一般都会和开发工具直接集成,如Idea。今天就介绍下idea和Docker如何集成。
有一只柴犬
2023/08/24
5290
04. Idea集成Docker
docker开启api访问,配置双向证书验证
Docker是一种容器化技术,可通过容器化技术提供的API进行访问和管理。您可以通过配置Docker API来开启对Docker API的访问,并使用双向证书验证确保通信的安全性。以下是配置Docker API以开启访问和双向证书验证的步骤:
堕落飞鸟
2023/03/31
1.9K0
harbor搭建企业docker私有镜像仓库
# curl -fsSL https://get.docker.com/ | sh
聂伟星
2020/07/12
2.8K0
Golang(十一)TLS 相关知识(二)OpenSSL 生成证书
0. 前言 接前一篇文章,上篇文章我们介绍了数字签名、数字证书等基本概念和原理 本篇我们尝试自己生成证书 参考文献:TLS完全指南(二):OpenSSL操作指南 1. OpenSSL 简介 OpenSSL 是一个开源项目,其组成主要包括三个组件: openssl:多用途的命令行工具 libcrypto:加密算法库 libssl:加密模块应用库,实现了ssl及tls OpenSSL 主要用于秘钥证书管理、对称加密和非对称加密 1.1 指令 常用指令包括:genrsa、req、x509 1.1.1 genrs
西凉风雷
2022/11/23
2.4K0
附008.Kubernetes TLS证书介绍及创建
Kubernetes系统的各个组件需要使用TLS证书对其通信加密以及授权认证,建议在部署之前先生成相关的TLS证书。
木二
2019/07/08
1.5K0
为GRPC证书加入双向证书认证如此简单
上一篇文章我们讲解了怎么给 GRPC 配置添加单向证书认证,这一篇我接着分享,如何让 GRPC 服务加入双向证书认证。
小锟哥哥
2022/05/10
1.9K0
为GRPC证书加入双向证书认证如此简单
docker remote api 加密
1. 设置主机名 编辑/etc/hostname,服务器主机名 zouyujie.top
用户9347382
2022/01/10
6240
推荐阅读
相关推荐
Linux开启Docker远程访问并设置安全访问(证书密钥),附一份小白一键设置脚本哦!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验