我们做app时候,有时候会遇到国际化需求,由于前期我们做项目时候是以单语种进行开发,这里说的单语种当然是中文了,这里我们列举几个常用的 Android 语种规范
1. 常见的语种
我们可以借助 AndroidStudio 去创建这样的目录,具体操作为:
- 选择
res
目录,右键,依次选择 New -> Android Resource Directory - 在弹出面板下的 Available qualifiers 下选择 Local,并且单击中间 >> 符号,Resource type 按默认的选择 valuse即可
- 看面板中以中文为例,依次选择 Language 中的 zh,接着选择 Specific Region Only 中的CN
点击OK后,我们就可以在 res目录看到values-zh-rCN
的目录了,当然这里也可以不需要选择最后一栏的 CN 也是可以的,选择 Specific Region Only 的最上行 Any Region即可去掉 rCN
从上面的步骤中,我们大致罗列几种开发中常见的语种
- values-en:英语语种
- values-fa:法语语种
- values-es:西班牙语种
- values-ja:日语语种
- values-zh-rTW:中国台湾
2. 国际化表格
这里我们用的是 xls
的表格来罗列国际化的语言字段,形如下表这样的 translation.xls
如果遇到非 xls 的表格,建议可以重写另存为一份 xls 表格
3. 自动生成相应资源文件
我们是基于 jxl
进行,所以还需要依赖一个 jxl:
dependencies{
implementation 'net.sourceforge.jexcelapi:jxl:2.6.12'
}
不多解释,直接上代码;
package com.monk.customlib
import jxl.Workbook
import jxl.WorkbookSettings
import java.io.BufferedWriter
import java.io.File
import java.io.FileWriter
/**
* @since 2022/08/31 20:02
* @author monk
*/
object TranslationTools {
@JvmStatic
fun main(args: Array<String>) {
val sheetNums = Workbook.getWorkbook(xlsFile, workbookSettings).numberOfSheets
for (sheetNum in 0 until sheetNums) {
// 第2列(column = B)开始国际化,一共有3列是需要国际化
handleXlsExcel(sheetNum, 1, 3)
}
}
private val codeMap: HashMap<Int, String> = HashMap()
private val keyAndValueMap: HashMap<String, ArrayList<TranslationBean>> = HashMap()
private const val DIR = "C:\\Users\\Administrator\\Desktop\\translation"
// 只支持 xls格式
private const val XLS_PATH = "$DIR\\translation.xls"
private val xlsFile = File(XLS_PATH)
private val workbookSettings = WorkbookSettings()
init {
if (codeMap.isNotEmpty()) codeMap.clear()
if (keyAndValueMap.isNotEmpty()) keyAndValueMap.clear()
// 这里设置为 utf-8 或者 gbk 或者 iso-885901,这里设置后者防止其它国家文字乱码
workbookSettings.encoding = "ISO-8859-1"
}
/**
* @param sheetNum: 表示sheet页数量(0表示第1张sheet)
* @param startColumn: 从0开始,第几列开始是国际化
* @param columnCount: 一共有多少列是国际化
*/
@kotlin.jvm.Throws(Exception::class)
fun handleXlsExcel(sheetNum: Int, startColumn: Int, columnCount: Int) {
// workbook 与 sheet 是一对一
val workbook: Workbook = Workbook.getWorkbook(xlsFile, workbookSettings)
val sheet = workbook.getSheet(sheetNum)
println("sheet0 = ${sheet.name}")
// 表示从第1行开始读取
for (row in 0 until sheet.rows) {
if (row == 0) {
for (column in 0 until columnCount) {
val columnIndex = startColumn + column
// B1, C1, D1单元格的内容表示国家代码
val code = sheet.getCell(columnIndex, row).contents
codeMap[columnIndex] = code
keyAndValueMap[code] = ArrayList()
}
} else {
// A1 ~ A[num] 单元格
val key = sheet.getCell(0, row).contents
if (key == null || "" == key) break
for (column in 0 until columnCount) {
val columnIndex = startColumn + column
val code = codeMap[columnIndex] ?: "null"
val bean = TranslationBean(
key,
sheet.getCell(columnIndex, row).contents
)
val translationList = keyAndValueMap[code]
translationList?.add(bean)
}
}
}
workbook.close()
val dir = File(DIR, sheet.name)
if (!dir.exists()) dir.mkdir()
for (code in keyAndValueMap.keys) {
val default = File(dir, "values-$code")
if (!default.exists()) default.mkdir()
val file = File(default, "strings.xml")
try {
if (!file.exists()) file.createNewFile()
val bw = BufferedWriter(FileWriter(file))
bw.write("<resources>")
bw.newLine()
keyAndValueMap[code]?.forEach { value ->
bw.write("<string name=\"${value.key}\">${value.value}</string>")
bw.newLine()
}
bw.write("</resources>")
bw.close()
println("生成成功...")
} catch (e: Exception) {
e.printStackTrace()
}
}
}
data class TranslationBean(
val key: String,
val value: String
)
}
效果如下
values-中文(values-zh-rCN)
values-日文(values-ja)
values-英文(values)
最后将生成的目录修改成规范化的目录,或者在一开始的 excel 表格中将 sheet 页定成android规范的语种也是可以的