预研

国际化对于只做国内市场的小伙伴来说基本没有太多感觉,但是对于做国外市场特别是谷歌市场的朋友来说却是需要重视的一个知识点。因为海外市场面对的全球的客户,而如果人工翻译势必很费时费力而且低效,这时候我们需要程序化来实现这个体力活。

有几种方案,一种是自己写一个程序或者脚本,接入翻译的api,比如google或者有道实现自动化查询转换。还有一种是拿现成的,这显然不知我有这个需求,大部分大众需求网上有热心朋友会做好,于是我选择第二种。

但是对于稍微大一点的公司来说,主要考虑的是分工的问题,而且要保证结果的准确性,用线上翻译软件不见得会有多准确,多数公司对翻译要求比较高,需要单独核对,而他们核对翻译通常不是在ide中,而是希望能有一个excel文件来存放对应的翻译数据,这个时候用一件翻译不见得是好事,那就要采用另外一种方法了,这个在后面会介绍。

通过插件实现国际化

选择国际化插件

如果我们在百度或者google上搜索Android Studio国际化,会有很多文章介绍如何实现国际化,但是大部分的文章并不一定奏效。当然我们自己也可以在Android Studio带的插件市场上搜索安装,最后我锁定在AndroidLocalizationer。

通常我找一个别人做好的工具,我会关注三点:

  1. 用的人多不多
  2. 更新的频次够不够高
  3. 现在是否还在维护

当然这都是出于实用主义,道理很简单,但是这三点再给我们找三方工具上会让我们少走很多弯路。

实际上我在Android studio上安装该插件后,我按照介绍说的右击string文件,他并没有生效而是弹出了一个警示框,然后没有了。开始我以为是网络问题,于是我连续试了两个梯子,全局代理都用了,并不能解决问题,于是我开始怀疑是不是版本错误了。

幸运的是,我在github上找到这个开源库并下载了旧版的release,然后神奇的发现旧版本的是可以用的。我这里用的是1.5,大概是两年前了吧,但是确实是蛮好用的,所以有时候最新的不一定好用,因为它有一些坑,而他的新功能我们自己又不一定用得到,所以大家要注意鉴别。

各国简称对照

简称/语言 简称/语言 简称/语言 简称/语言
aa 阿法尔语 fr 法语 li 林堡语 se 北萨米语
ab 阿布哈兹语 fy 弗里西亚语 ln 林加拉语 sg 桑戈语
ae 阿维斯陀语 ga 爱尔兰语 lo 老挝语 sh 塞尔维亚-克罗地亚语
af 南非语 gd 苏格兰盖尔语 lt 立陶宛语 si 僧加罗语
ak 阿坎语 gl 加利西亚语 lu 卢巴语 sk 斯洛伐克语
am 阿姆哈拉语 gn 瓜拉尼语 lv 拉脱维亚语 sl 斯洛文尼亚语
an 阿拉贡语 gu 古吉拉特语 mg 马达加斯加语 sm 萨摩亚语
ar 阿拉伯语 gv 马恩岛语 mh 马绍尔语 sn 绍纳语
as 阿萨姆语 ha 豪萨语 mi 毛利语 so 索马里语
av 阿瓦尔语 he 希伯来语 mk 马其顿语 sq 阿尔巴尼亚语
ay 艾马拉语 hi 印地语 ml 马拉亚拉姆语 sr 塞尔维亚语
az 阿塞拜疆语 ho 希里莫图语 mn 蒙古语 ss 斯瓦特语
ba 巴什基尔语 hr 克罗地亚语 mo 摩尔达维亚语 st 南索托语
be 白俄罗斯语 ht 海地克里奥尔语 mr 马拉提语 su 巽他语
bg 保加利亚语 hu 匈牙利语 ms 马来语 sv 瑞典语
bh 比哈尔语 hy 亚美尼亚语 mt 马耳他语 sw 斯瓦希里语
bi 比斯拉马语 hz 赫雷罗语 my 缅甸语 ta 泰米尔语
bm 班巴拉语 ia 国际语 A na 瑙鲁语 te 泰卢固语
bn 孟加拉语 id 印尼语 nb 书面挪威语 tg 塔吉克斯坦语
bo 藏语 ie 国际语 E nd 北恩德贝勒语 th 泰语
br 布列塔尼语 ig 伊博语 ne 尼泊尔语 ti 提格里尼亚语
bs 波斯尼亚语 ii 四川彝语 (诺苏语 ) ng 恩敦加语
ca 加泰隆语 ik 依努庇克语 nl 荷兰语 tl 他加禄语
ce 车臣语 io 伊多语 nn 新挪威语 tn 塞茨瓦纳语
ch 查莫罗语 is 冰岛语 no 挪威语 to 汤加语
co 科西嘉语 it 意大利语 nr 南恩德贝勒语 tr 土耳其语
cr 克里语 iu 因纽特语 nv 纳瓦霍语 ts 宗加语
cs 捷克语 ja 日语 ny 尼扬贾语 tt 塔塔尔语
cu 古教会斯拉夫语 jv 爪哇语 oc 奥克语 tw 特威语
cv 楚瓦什语 ka 格鲁吉亚语 oj 奥吉布瓦语 ty 塔希提语
cy 威尔士语 kg 刚果语 om 奥洛莫语 ug 维吾尔语
da 丹麦语 ki 基库尤语 or 奥利亚语 uk 乌克兰语
de 德语 kj 宽亚玛语 os 奥塞梯语 ur 乌尔都语
dv 迪维希语 kk 哈萨克语 pa 旁遮普语 uz 乌兹别克语
dz 不丹语 kl 格陵兰语 pi 巴利语 ve 文达语
ee 埃维语 km 高棉语 pl 波兰语 vi 越南语
el 现代希腊语 kn 卡纳达语 ps 普什图语 vo 沃拉普克语
en 英语 ko 朝鲜语 、韩语 pt 葡萄牙语
eo 世界语 kr 卡努里语 qu 凯楚亚语 wo 沃洛夫语
es 西班牙语 ks 克什米尔语 rm 罗曼什语 xh 科萨语
et 爱沙尼亚语 ku 库尔德语 rn 基隆迪语 yi 依地语
eu 巴斯克语 kv 科米语 ro 罗马尼亚语 yo 约鲁巴语
fa 波斯语 kw 康沃尔语 ru 俄语 za 壮语
ff 富拉语 ky 吉尔吉斯语 rw 卢旺达语 zh 中文、汉语
fi 芬兰语 la 拉丁语 sa 梵语 zu 祖鲁语
fj 斐济语 lb 卢森堡语 sc 萨丁尼亚语
fo 法罗语 lg 卢干达语 sd 信德语

各国语言对照

国家/地区 语言代码 国家/地区 语言代码
简体中文(中国) zh-cn 繁体中文(台湾地区) zh-tw
繁体中文(香港) zh-hk 英语(香港) en-hk
英语(美国) en-us 英语(英国) en-gb
英语(全球) en-ww 英语(加拿大) en-ca
英语(澳大利亚) en-au 英语(爱尔兰) en- ie
英语(芬兰) en-fi 芬兰语(芬兰) fi-fi
英语(丹麦) en-dk 丹麦语(丹麦) da-dk
英语(以色列) en-il 希伯来语(以色列) he-il
英语(南非) en-za 英语(印度) en-in
英语(挪威) en-no 英语(新加坡) en-sg
英语(新西兰) en-nz 英语(印度尼西亚) en-id
英语(菲律宾) en-ph 英语(泰国) en-th
英语(马来西亚) en-my 英语(阿拉伯) en-xa
韩文(韩国) ko-kr 日语(日本) ja-jp
荷兰语(荷兰) nl-nl 荷兰语(比利时) nl-be
葡萄牙语(葡萄牙) pt-pt 葡萄牙语(巴西) pt-br
法语(法国) fr-fr 法语(卢森堡) fr-lu
法语(瑞士) fr-ch 法语(比利时) fr-be
法语(加拿大) fr-ca 西班牙语(拉丁美洲) es- la
西班牙语(西班牙) es-es 西班牙语(阿根廷) es-ar
西班牙语(美国) es-us 西班牙语(墨西哥) es-mx
西班牙语(哥伦比亚) es-co 西班牙语 (波多黎各) es-pr
德语(德国) de-de 德语(奥地利) de-at
德语(瑞士) de-ch 俄语(俄罗斯) ru-ru
意大利语(意大利) it-it 希腊语( 希腊) el- gr
挪威语(挪威) no-no 匈牙利语(匈牙利) hu-hu
土耳其语(土耳其) tr-tr 捷克语(捷克共和国) cs- cz
斯洛文尼亚语 sl-sl 波兰语(波兰) pl-pl
瑞典语(瑞典) sv-se 西班牙语 (智利) es-cl
越南 vi_VN

执行

由于通过http实现转换,因此转换的时候会比较慢,大家尽量只勾选需要发布的那几个国家就行。

插件只会显示简称,因此注意对照上面的表执行。

通过读取Excel生成string

相比于上面的一键生成,这种方式要麻烦很多,但确实是很多大公司使用的方式,因为这种方式分工明确,准确度高,所以如果对翻译要求比较高的团队还是推荐使用这种方法。

这里分为三步骤:

  • 编写对应格式的Excel文档
  • 使用脚本解析
  • 使用脚本自动复制替换项目中的string

Excel格式定义

网上的普遍做法是将翻译好的数据卸载excel文件中,格式基本都是下面这样:

注意:excel文件的编写是由格式要求的,主要体现为:

  1. 前面是对应字符串的需要,用于生成string名字的
  2. 里面的内容如果有占位符,是通过&value的方式,具体对照下面的脚本文件可自行修改称自己的格式。
  3. 纵向是各语言对应的翻译。

执行转换脚本

然后通过编写脚本文件读取对应的行和列,写入到string文件中。使用的预研可能是Java也可能是python,用这两种语言的都不少。以python为例:

import xlrd
import re
import os#配置了多国语言的xls文件,必须是xls后缀名的文件 */
sourceFile = os.path.abspath('my.xlsx')
#输出文件夹 */
enterDir = os.path.abspath(os.path.dirname(sourceFile) + os.path.sep + ".")
#第几张表 */
sheetNum = ( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 23, 25, 26, 27, 28, 29, 30,31, 32, 33, 34, 35, 36, 37, 38, 39, 40);localeMap = {'简体中文':'zh-rCN','English':'en-rUS','Deutsch':'de-rDE','法语':'fr-rFR','Spanish':'es-rES','捷克语':'cs-rCZ','保加利亚语':'bg-rBG','罗马尼亚语':'ro-rRO','葡萄牙':'pt-rPT','Italian':'it-rIT'}isSkip = True
skipSet = ("s14_38", "s22_22", "s23_19")def write():# 构建Workbook对象, 只读Workbook对象# 直接从本地文件创建Workbookreadwb = xlrd.open_workbook(sourceFile)# Sheet的下标是从0开始# 获取第一张Sheet表list = []for i in range(len(sheetNum)):readsheet = readwb.sheets()[sheetNum[i]]prefix = "s" + str(sheetNum[i]) + "_"# 获取Sheet表中所包含的总列数columns = readsheet.ncols# 获取Sheet表中所包含的总行数rows = readsheet.nrowsfor index in range(columns):list.append(XmlObj())for row in range(rows):for col in range(columns):cell = readsheet.cell(row, col)name = "s"cell0Row = str(readsheet.cell(row, 0).value)reg = "\\d+";p = re.compile(reg)num = ""nums = p.findall(cell0Row)if nums:# 只找到最后的数字num = nums[0]name = prefix + numif isSkip and name in skipSet:continue;if row != 1 and isEmpty(num):continuevalue = str(cell.value)#替换换行value = value.replace("\n", "\\n")if "&value&" in value or "& value &" in value:value = value.replace("%", "%%")value = re.sub("& *value *&", "%1$s", value)value = re.sub("& *value1 *&", "%1$s", value)value = re.sub("& *value2 *&", "%2$s", value)value = re.sub("& *value3 *&", "%3$s", value)value = re.sub("& *value4 *&", "%4$s", value)value = value.replace("&", "&amp;")value = value.replace("<br>", "\\n")value = value.replace("\"", "\\\"")value = value.replace("'", "\\'")value = value.replace("@", "\\@")hasHtmlTag = "<span " in valuer = re.compile(".*\\[.*].*")match = r.match(value)if match:value = value.replace("\\n", "<br>")value = value.replace("[", "<a href=\"{url}\">")value = value.replace("]", "</a>")hasHtmlTag = Trueif hasHtmlTag:value = "<![CDATA[" + value + "]]>"if row == 1:list[col].fileName = localeMap.get(value, value)else:if isEmpty(list[col].fileName) or isEmpty(value) and list[col].fileName != 'en-rUS':continueenter = Trueif row == rows - 1:enter = Falselist[col].content = list[col].content + getTag(name, value, enter)for item in list:if isEmpty(item.fileName):continuewriteXml(item.fileName, item.content)print("success")returndef writeXml(fileName,str):dir = enterDir + "/语言/" + fileNameif not os.path.exists(dir):os.makedirs(dir)f = open(dir + "/" + "strings.xml", "w+", encoding="utf-8")f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n" + str + "</resources>\n")f.closedef getTag(name,str,enter):if isEmpty(name):return ""s = "<string name=" + "\"" + name + "\">" + str + "</string>"if enter:s += "\n"return sdef isEmpty(s):if not s.strip():return Truereturn Falseclass XmlObj:fileName = ""content = ""write()

执行复制脚本

这个时候,他会在对应的目录生成string文件,如果你希望自动把谢谢文件移动到你的项目中,你可以通过一个sh脚本实现:

dir=`dirname $0`
work='E://AndroidStudioProject/MyApplication'
cp $dir/语言/en-rUS/strings.xml $work/MyApplication/app/src/main/res/values
cp $dir/语言/en-rUS/strings.xml $work/MyApplication/app/src/main/res/values-en
cp $dir/语言/it-rIT/strings.xml $work/MyApplication/app/src/main/res/values-it
cp $dir/语言/pt-rPT/strings.xml $work/MyApplication/app/src/main/res/values-pt
cp $dir/语言/zh-rCN/strings.xml $work/MyApplication/app/src/main/res/values-zh
cp $dir/语言/es-rES/strings.xml $work/MyApplication/app/src/main/res/values-es
cp $dir/语言/de-rDE/strings.xml $work/MyApplication/app/src/main/res/values-de

这个我就不解释了,相信大家都看的懂。然后就大功告成了。

AndroidStudio一键国际化方案相关推荐

  1. Angular国际化方案

    Angular国际化方案 首先和大家推荐一个xlf文件的操作工具,支持合并和编辑功能,github,到release界面下载. 对于Angular国际化,官方提供了i18n方案,也就是标签的方式,通过 ...

  2. vue使用element-ui开发的后台管理系统使用中英文切换多语言国际化方案步骤流程

    公司后台管理系统需要使用多语言版本,本次记录使用i18n实现多语言切换的流程步骤: 1.安装工具包 npm install vue-i18n 2.在项目src目录下新建lang文件夹,目录结构如下: ...

  3. RCL0923分布式光伏群调群控终端装置-即光伏协议转换器(完成逆变器数据采集协议规约转换功能)+台区智能融合终端SCU实现分布式光伏群调群控-分布式光伏可观可测可控一键群调,一键群控方案介绍

    RCL0923分布式光伏群调群控装置-即光伏协议转换器(完成逆变器数据采集协议规约转换功能)+台区智能融合终端SCU实现分布式光伏群调群控-分布式光伏可观可测可控一键群调,一键群控方案介绍 一.分布式 ...

  4. web系统国际化方案

    web系统国际化方案 前言 很多时候一个系统发展到一定环境,就需要兼容到各种各样的国家.而这种兼容除了语言,还包含时区,数据,还有服务器速度等. 其实需要考虑的东西也蛮多的,我最近因为做外国服系统,所 ...

  5. DTCloud 一键部署方案

    dtcloud_install 一键部署方案 原文件名称为 DTCloud git dt_install --help dt_install 从一个内置地址获取源代码,安装PostgreSQL,pyt ...

  6. 美摄推出一键成片方案,智能化创作提升视频生产效率

    北京冬奥会已落下帷幕,赛场上奥运健儿们展现了飒爽英姿,赛场外也掀起了一股冰雪运动热潮,网友们拍摄的滑雪Vlog占据了多个视频网站的首页.对于普通用户来说,剪辑工具中模板的存在大大降低了视频创作的门槛, ...

  7. Vue-i18n与Vuex-i18n等vue的国际化方案

    Vue-i18n与Vuex-i18n等国际化方案 文档时间:2021-01-04 vue-i18n和vuex-i18n两者皆为vue项目的国际化方案. 文章目录 Vue-i18n与Vuex-i18n等 ...

  8. android studio迁移,AndroidStudio 一键迁移至 AndroidX

    在上篇文章 <关于 MVPArms 兼容 AndroidX 的问题> 中,我犯了一个致命的错误. 我没升级 AndroidStudio 到最新版, 是的, 我的 AndroidStudio ...

  9. 免外围电路ESP32/ESP8266系列单片机串口一键下载方案

    一.概述 CH340X.CH343.CH342等USB转串口芯片支持免外围电路ESP32/ESP8266等单片机串口一键下载功能,对此类支持多模式启动的单片机,无需外围三极管等逻辑控制电路,将芯片提供 ...

  10. 免外围电路CH32F/CH32V/STM32F系列单片机串口一键下载方案(CH340)

    一.概述 CH340X和CH340C等USB转串口芯片提供专用下载模式,可实现免外围电路CH32F/CH32V/STM32F等单片机串口一键下载功能,对此类支持多模式启动的单片机,无需外围三极管等逻辑 ...

最新文章

  1. Linux pip安装包。解决:You should consider upgrading via the 'pip install --upgrade pip' command.
  2. 证券期货交易高并发模型
  3. [导入]深入了解OpenOffice.org(二){作者:路广}
  4. 高动态范围图像-单图
  5. HDU 4332 Constructing Chimney [状态压缩+矩阵]
  6. 研究发现视频会议增加员工压力、 谷歌地球升级4D交互体验、Apple新品发布、网飞用户增长缓慢等|Decode the Week
  7. python3读取网页_python3+selenium获取页面加载的所有静态资源文件链接操作
  8. 单片机实验用c语言编写计算器,单片机实验报告计算器.doc
  9. GATK / 体细胞短变异检测工具Mutect2的使用
  10. python pandas向已有excel添加新表sheet/添加数据
  11. 为什么我不建议你裸辞做自媒体?
  12. uni-app 文件选择、文件管理器(ios11)
  13. 帝国cms 留言反馈 问题
  14. 数据库编程入门培训(一)
  15. 关于Windows PowerShell
  16. 《计算机网络自顶向下方法》读书笔记(五):链路层和局域网
  17. 基于Faster-RCNN的水书古籍手写文字的检测与识别-论文阅读
  18. 浅谈 RISC-V 软件开发生态之 IDE
  19. 新手Python入门经典书籍推荐
  20. PMP报名需要注意什么?特别提醒

热门文章

  1. DCB差分码偏差概念及应用(附RTKLIB测试对比结果)
  2. 采集插件,自动采集伪原创发布插件
  3. Linux中文显示乱码问题解决方法(编码查看及转换)
  4. IIS不能启动的原因
  5. threejs包围盒的应用
  6. Linux服务器使用网络代理
  7. Xcode 使用手册之01 欢迎使用Xcode(Xcode中文文档手册)
  8. JS API: Fullscreen 全屏 API
  9. java毕业设计户籍管理系统mybatis+源码+调试部署+系统+数据库+lw
  10. 信号与系统 徐亚宁 matlab程序,信号与系统分析 [徐亚宁,李和主编] 2010年版