软件多语言文案脚本自动化方案
开发高效提速系列目录
- 软件多语言文案脚本自动化方案
软件多语言文案脚本自动化方案
- 背景
- 目标
- 整体方案
- 1. 创建文案资源文件
- 2. python脚本开发
- 3. Python脚本执行与管理
- 4. 人员职责分配
- PyCharm使用说明
- 1. PyCharm下载
- 2. PyCharm安装配置
- 3. 异常情况解决
- 总结
博客创建时间:2023.05.03
博客更新时间:2023.05.03
以Android studio gradle=7.5,SDKVersion 32来分析讲解。如图文和网上其他资料不一致,可能是别的资料版本较低而已。
背景
在海外项目中多语言的支持是很重要的一部分。在我们的项目中常常需要支持简中、繁体、英、日、韩、西班牙语等十多种语言,当我们进行文案的新增、修改、删除时,需要在软件项目多语言文案资源文件中进行文案Key和文案内容对应的复制粘贴,非常耗时耗力且容易出现疲劳性错误。
目前关于多语言文案的管理,有部分公司的项目管理可能还停留在如下流程中:
-
文案由开发在项目资源文件中进行维护(如Android的strings.xml、IOS的Localizable.strings、PC云端的XXX.ini ),当需要进行文案翻译时,将文案文件语言.xml文件给到产品经理
-
由产品经理经过其他操作对文案进行翻译,提供多语言翻译后的excel文档给到软件开发,此时文案Key和文案内容失去关联关系
-
软件开发根据给到的翻译内容查找到对应的文案Key,然后复制到对应的资源文件中进行文案的更新操作
该流程实现过程中,会出现可能的几点问题:
- 在版本开发迭代期间,频繁的文案新增修改,需要开发人员频繁手动对齐文案和Key的关系,费时费力
- 每一中语言都需要将操作重复进行一遍,语言种类越多耗时越久且手动复制粘贴中容易出现疲劳性错误
目标
为了方便对文案资源进行统一管理,方便产品、开发、测试对文案内容的统一对齐,应该在已有的翻译excel文档的基础上完善文案,对每条文案新增对应的文案Key,同时采用python脚本方法,实现脚本自动化程序更新文案资源,达到提升文案管理和使用效率提升。该方案可以支持Android、IOS、PC云端项目的。
整体方案
该方案的主要思路是:
- 创建好统一管理Android、IOS或PC 云端项目的文案管理excel文件
- 根据文案资源Excel文件进行python脚本的编写,达到执行脚本时能生成不同格式的文案资源文件
- 当文案资源有更新时,在excel文档中进行更新,执行脚本程序完成文案资源的更新
根据思路我将其细分为如下几个细分步骤:
- 建立标准化文案管理文件。一般是用excel文件管理
- 编写Python脚本开发
- Python文件管理与程序触发执行
- 项目组内人员职责分配
1. 创建文案资源文件
多语言文案可以放在某个excel文件中进行管理,一般使用公司的办公软件如钉钉或飞书软件中进行管理。文案资源的格式可以一般同产品沟通协商共同制作,符合自己公司产品的需求即可,我这里给出移动端文案sheet和PC 云端sheet模板样式,云端和移动端因文案差异太大,建议不用放在一起。
注意:多语言的文案翻译根据软件的实际需求进行使用,如软件不支持某种语言如"土耳其语",将其对应列空着即可。
2. python脚本开发
python脚本代码如下
# coding=utf-8
import importlib
import re
import sys
import os
import xlrd2importlib.reload(sys)
# isAndroid = True
ANDROID = "Android"
IOS = "IOS"
PC = "PC"
# 配置文件修改区 START *****/
# 平台类型 Android、IOS、PC 区分大小写
platformType = "Android"# 项目多语言资源文件
excelPath = os.path.expanduser('~/Downloads/多语言文案.xlsx')
# 输出路径
outputPath = "D:/Ken.Luo/res/"# 选择需要导出文案的sheet名
sheetName = "App文案"
# 配置文件修改区 END *****/# 导出文案的类型
# entryType = "Android"
commentColNum = 4
typeColNum = 2
keyColNum = 2
colToStringsMap = None# 切换到iOS
def switchToAndroid():global keyColNum, colToStringsMapkeyColNum = 2# 对应关系元组Android (列数 : 多语言文件)colToStringsMap = [(7, "values/strings.xml"),(5, "values-zh/strings.xml"),(6, "values-zh-TW/strings.xml"),(8, "values-de/strings.xml"),(9, "values-fr/strings.xml"),(10, "values-es/strings.xml"),(11, "values-ja/strings.xml"),(12, "values-ko/strings.xml"),(13, "values-ar/strings.xml"),(14, "values-it/strings.xml"),(15, "values-pt/strings.xml"),(16, "values-tr/strings.xml"),(17, "values-ru/strings.xml")]# 切换到iOS
def switchToIOS():global keyColNum, colToStringsMapkeyColNum = 3colToStringsMap = [(7, "values/Localizable.strings"),(5, "values-zh/Localizable.strings"),(6, "values-zh-TW/Localizable.strings"),(8, "values-de/Localizable.strings"),(9, "values-fr/Localizable.strings"),(10, "values-es/Localizable.strings"),(11, "values-ja/Localizable.strings"),(12, "values-ko/Localizable.strings"),(13, "values-ar/Localizable.strings"),(14, "values-it/Localizable.strings"),(15, "values-pt/Localizable.strings"),(16, "values-tr/Localizable.strings"),(17, "values-ru/Localizable.strings")]def switchToPC():global keyColNum, colToStringsMapkeyColNum = 2colToStringsMap = [(7, "values/strings.ini"),(5, "values-zh/strings.ini"),(6, "values-zh-TW/strings.ini"),(8, "values-de/strings.ini"),(9, "values-fr/strings.ini"),(10, "values-es/strings.ini"),(11, "values-ja/strings.ini"),(12, "values-ko/strings.ini"),(13, "values-ar/strings.ini"),(14, "values-it/strings.ini"),(15, "values-pt/strings.ini"),(16, "values-tr/strings.ini"),(17, "values-ru/strings.ini")]# ******* #def formatValue(originalStr):''' 格式化字符串成为app 程序需要的样子'''print("originalStr:" + originalStr)# excel中的换行符换成 \n转义字符, 文案首尾的换行符认为是翻译人员不小心按出来的,在此去掉originalStr = re.sub(r'\n+$', "", originalStr, re.S)originalStr = re.sub(r'^\n+', "", originalStr, re.S)originalStr = re.sub(r'\n', "\\\\n", originalStr, re.S)# 安卓需要对&进行处理if platformType is ANDROID:# 不处理,待后续直接替换成空格if originalStr != ' ':originalStr = re.sub(r'&', "&", originalStr, re.S)print("")return originalStr### 写多语言文件函数 ###
def write_header(strFile):if platformType is ANDROID:strFile.write("""<?xml version="1.0" encoding="utf-8" ?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">\n""")def write_trailer(strFile):if platformType is ANDROID:strFile.write("\n</resources>")def write_comment(strFile, comment):'''生成注释文案'''if comment != "" and comment != None:if platformType is ANDROID:strFile.write("\t<!-- " + str(comment) + "-->\n")elif platformType is IOS:strFile.write("/** " + str(comment) + " */\n")elif platformType is PC:strFile.write("# " + str(comment) + " \n")def write_key_value(strFile, key, value, defaultValue):# iOS对于value是空使用defaultValueif value == " ":value = " "if not typeColNum is ANDROID and (value is None or value == ""):value = defaultValueif key is None or key == "" or value is None or value == "":return# 处理一个文案多个key的情况keyColValues = key.splitlines()for keyColValue in keyColValues:if platformType is ANDROID:strFile.write("\t<string name=\"" + keyColValue.strip() + "\">" + value.strip() + "</string>\n")elif platformType is IOS:strFile.write("\"" + keyColValue.strip() + "\" = \"" + value.strip() + "\";\n")elif platformType is PC:strFile.write(keyColValue.strip() + " = \"" + value.strip() + "\";\n")# ******* #
workbook = xlrd2.open_workbook(excelPath)
table = workbook.sheet_by_name(sheetName)def writeToFiles():nrows = table.nrows# 打开文件colToFileMap = []for (col, fileName) in colToStringsMap:paths = os.path.split(fileName)print("paths 路径", paths)if len(paths) > 1:pathDir = outputPath + paths[0]print("dir 路径", pathDir)# 输出目录文件夹不存在就创建if not (os.path.exists(pathDir)):os.makedirs(pathDir)file = open(outputPath + fileName, "w+", 1024, "utf-8")colToFileMap.append((col, file))write_header(file)# 导出文案for i in range(2, nrows):print(table)comment = table.cell(i, commentColNum).valuetypeColValue = table.cell(i, typeColNum).valuekeyColValue = table.cell(i, keyColNum).valuedefaultValue = ""# 将一行的各列写入对应的多语言文件for (col, strFile) in colToFileMap:value = table.cell(i, col).valuevalue = formatValue(value)if col == colToFileMap[0][0]:defaultValue = valuewrite_comment(strFile, comment)# if typeColValue.find(entryType) >= 0:write_key_value(strFile, keyColValue, value, defaultValue)# 关闭文件for (_, file) in colToFileMap:write_trailer(file)file.close()if __name__ == '__main__':if platformType is ANDROID:switchToAndroid()writeToFiles()elif platformType is IOS:switchToIOS()writeToFiles()elif platformType is PC:switchToPC()writeToFiles()
3. Python脚本执行与管理
Python脚本的执行需要在电脑中进行触发程序执行,需要电脑有python运行环境,我使用的是Pycharm idea软件,一键安装即可用,和Android studio使用是一样的。后面会专门讲解PyCharm的使用操作。
参数配置
当执行软件安装好后,需要进行部分参数的配置,配置完参数后即可进行程序的执行,生成对应的资源文件。
ANDROID = "Android"
IOS = "IOS"
PC = "PC"
# 配置文件修改区 START *****/
# 平台类型 Android、IOS、PC 区分大小写
platformType = "PC"# 项目多语言资源文件
excelPath = os.path.expanduser('~/Downloads/Remo文案汇总.xlsx')
# 输出路径
outputPath = "D:/Ken.Luo/res88888/"# 选择需要导出文案的sheet名
sheetName = "APP文案"
# 配置文件修改区 END *****/
主要修改的是参数为
- platformType:资源使用的平台,目前定义有Android、IOS、PC云端
- excelPath :excel资源文件的目录地址
- outputPath:脚本执行后的生成的输出位置
- sheetName :APP和PC云端的文案资源我设计是分开放的,所以是两个sheet,需要执行程序时手动选择
执行效果
以Android举例,多语言文案资源是放置在res/value/strings.xml文件中下的。现在我们预计通过执行python脚本程序,实现文案内容自动更新到各语言的strings.xml中。
脚本管理
python脚本是为了减少开发进行文案更新时提效的,当脚本程序开发完毕后考虑后期可能有优化,需要对齐进行持久化管理,所以首先想到的是使用gitee进行管理。https://gitee.com/luofaxin/LanguageRes.git
4. 人员职责分配
在多语言文案管理中,不同角色有自己的任务分配
PyCharm使用说明
在python脚本准备好后,需要通过某种方式实现程序的触发,第一阶段先考虑手动操作pycharm程序执行脚本程序,后期也可以考虑在服务器上进行脚本的自触发。
1. PyCharm下载
手动触发方式需要使用者安装Pycharm 软件,用于执行文案脚本程序。https://www.jetbrains.com/pycharm/download/#section=windows
2. PyCharm安装配置
-
配置.py运行环境
-
配置脚本执行变量
对于.py文件,需要动态的更改路径的配置
-
执行脚本程序
点击执行脚本程序,python脚本将会自动执行,将excel文件生成res/strings.xml文件
3. 异常情况解决
- Python ModuleNotFoundError: No module named ‘xlrd‘ 异常
解决方案
总结
希望这个python脚本自动化方案能帮助大家,多语言文案资源和pyhton脚本我都放到gitee仓库中了,可以下载使用。欢迎大家提出更好的优化建议。
仓库地址:https://gitee.com/luofaxin/LanguageRes.git
相关链接:
- 软件多语言文案脚本自动化方案
扩展链接:
- 项目开发混淆从初识到理解
- 项目开发代码分支管理
博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !
相关文章:
软件多语言文案脚本自动化方案
开发高效提速系列目录 软件多语言文案脚本自动化方案 软件多语言文案脚本自动化方案 背景目标整体方案1. 创建文案资源文件2. python脚本开发3. Python脚本执行与管理4. 人员职责分配 PyCharm使用说明1. PyCharm下载2. PyCharm安装配置3. 异常情况解决 总结 博客创建时间&…...
C++017-C++文件读写应用
文章目录 C017-C文件读写应用C文件读写应用CSP-J目标1. 文件的基本概念、文本文件的基本操作2.文本文件类型与二进制文件类型文本文件类型二进制文件类型二进制查看工具 3.文件重定向、文件读写等操作关闭文件文件操作-写入文本文件文件操作-读取文本文件文件操作-写入二进制文…...
计算机网络 实验二
⭐计网实验专栏,欢迎订阅与关注! ★观前提示:本篇内容为计算机网络实验。内容可能会不符合每个人实验的要求,因此以下内容建议仅做思路参考。 一、实验目的 (1)掌握IP地址的基本结构(网络部分与主机部分的…...
Unity 3D 学习笔记(1)
文章目录 1.Unity 3D 概述2.Unity的安装过程3.Unity 3D 的项目管理4.Unity 3D 中的场景5.Unity 3D 的界面组成 1.Unity 3D 概述 Unity 3D简介:Unity 3D是虚拟现实行业中使用率较高的一款开发引擎,由Unity Technology公司开发。通过Unity,开发…...
P1050 [NOIP2005 普及组] 循环
题目描述 乐乐是一个聪明而又勤奋好学的孩子。他总喜欢探求事物的规律。一天,他突然对数的正整数次幂产生了兴趣。 众所周知,22 的正整数次幂最后一位数总是不断的在重复 2,4,8,6,2,4,8,6…2,4,8,6,2,4,8,6… 我们说 22 的正整数次幂最后一位的循环长度…...
软考算法-排序篇-上
数据排序 一:故事背景二:直接插入排序2.1 概念2.2 画图表示2.3 代码实现2.4 总结提升 三:希尔排序3.1 概念3.2 画图表示3.3 代码实现3.4 总结提升 四:直接选择排序4.1 概念4.2 画图表示4.3 代码实现4.4 总结提升 五:堆…...
总结836
学习目标: 4月(复习完高数18讲内容,背诵21篇短文,熟词僻义300词基础词) 学习内容: 暴力英语:背诵《keep your direction》,默写,英语语法 高等数学:刷题&a…...
ginbuilder 工具快速创建
ginbuilder github 地址 快速创建一个ginweb项目: 目前apps下只有http服务,如果后续有需要的话,会添加上rpc服务,websocket服务后边如果有需要会添加上swagger 创建完成的目录结构 ├── apps │ ├── apis // 所有的apis…...
【Java基础面试宝典】堆、栈、方法区分别都存储了那些内容?wait 和 sleep 方法的区别?
目录 堆、栈、方法区分别都存储了那些内容? 堆(heap) 栈(stack) 方法区(method) 在 java 中 wait 和 sleep 方法的区别? 堆、栈、方法区分别都存储了那些内容? 堆&a…...
古剑飞仙手游Linux系统服务器架设教程
安装宝塔直接运行命令即可。 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh 搭建环境: centos 7以上系统服务器 宝塔面板安装应用如下: Nginx1.14 mysql5.7 php5.6 1…...
python实战应用讲解-【numpy数组篇】常用函数(十)(附python示例代码)
目录 Python Numpy MaskedArray.ravel()函数 Python Numpy MaskedArray.reshape()函数 Python Numpy MaskedArray.resize()函数 Python Numpy MaskedArray.std()函数 Python Numpy MaskedArray.sum()函数 Python Numpy MaskedArray.swapaxes()函数 Python Numpy MaskedA…...
计算机组成原理(考研408)练习题#2
用于复习408或计算机组成原理期末考试。如有错误请在评论区指出。 So lets start studying with questions! それでは、問題の勉強を始めましょう! 11.某 cache 采用全相联映射,假设 cache 有 3 块,程序运行过程中需要访问的主存块号依 次为…...
Apache POI,springboot中导出excel报表
2. Apache POI 2.1 介绍 Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。简单来说就是,我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。 一般情况下,POI 都是用于操作 Excel 文件。 Apache POI 的应用场景…...
CSS(一)-- 三种样式表
目录 1. 行内样式表 2. 内部样式表 3. 外部样式表(即引入 .css文件)(重点掌握) 1. 行内样式表 行内样式表(内联样式表)是在元素标签内部的 style 属性中设定 CSS 样式。适合于修改简单样式。 <di…...
嵌入式之Samba服务器搭建
在嵌入式系统开发应用平台中,tftp、nfs和samba服务器是最常用的文件传输工具 tftp和nfs是在嵌入式Linux开发环境中经常使用的传输工具 samba则是Linux和Windows之间的文件传输工具。 下面演示在linux上搭建Samba服务器 sudo apt-get install samba chmod -R 77…...
vue3+go——看到了就去学习吧
vue3go——看到了就去学习吧 Vue3.2 Vite Element-Plus 实现最基础的 CRUD1.效果展示【02:36】2.创建项目【03:16】3.添加github管理【04:10】4.引入element-plus【04:21】5.内容布局【08:59】6.布局优化【05:31】7.添加弹窗【09:34】8.ref改$ref【02:47】9.新增数据【09:22】…...
Perf工具统计CPU性能
Perf 性能检测工具 Perf 是一个内置于Linux内核中的工具,用于性能分析和调优。它可以对系统的CPU使用情况、内存使用情况、磁盘I/O、网络I/O等进行监控和分析,并提供了丰富的分析和可视化工具,以帮助用户定位和解决性能问题。perf可以进行函…...
考验大家指针功底的时候到了:请问如何理解 (int*)1 + 1 ?
来,猜猜看,这里的执行结果是什么? 这是今天课上的一道理解题,给大家一点点思考时间。 (心里有答案了再往下滑哦) 5 4 3 2 1 . 答案是,报warning!因为%d不是用来输出指针的哈…...
英语基础-介词
介词 方位介词 in:在…里面 Its in the box. 在盒子里 in my backpack 在背包里 in the tree 长在树上on:在…上面(指与物体表面接触) Its on the box. 在盒子上(和盒子接触) on the floor.在地板上 on the tree.在树上under:在…下面 Its unde…...
Linux进程通信:进程组 会话
1. 进程组 (1)概念:一个或多个进程的集合,也称为“作业”。 (2)父进程创建子进程时,默认属于同一个进程组。进程组ID为组长进程ID。 (3)进程组中只要有一个进程存在&a…...
【前端面经】JS-深浅拷贝
理解深浅拷贝 深浅拷贝问题的出现是由于JavaScript对不同类型的存储方式而引发的。 对于原始数据类型,它们的值是直接存储在栈内存中; 而复杂数据类型,则在栈内存中记录它的指针,而指针指向堆内存中真正的值。 所以对于原始数据类…...
【自然语言处理】实验2布置:Word2Vec TransE案例
NLP_class 学堂在线《自然语言处理》实验课代码报告,授课老师为刘知远老师。课程链接:https://www.xuetangx.com/training/NLP080910033761/1017121?channeli.area.manual_search。 持续更新中。 所有代码为作者所写,并非最后的“标准答案…...
Redis集合底层实现原理
目录 本章重点简单动态字符串SDS集合底层实现原理zipListlistPackskipListquickListKey 与Value中元素的数量 本章重点 掌握Redis简单动态字符串了解Redis集合底层实现原理 简单动态字符串SDS SDS简介 我们Redis中无论是key还是value其数据类型都是字符串.我们Redis中的字符…...
OVS常用命令与使用总结
OVS常用命令与使用总结 说明 在平时使用ovs中,经常用到的ovs命令,参数,与举例总结,持续更新中… 进程启动 1.先准备ovs的工作目录,数据库存储路径等 mkdir -p /etc/openvswitch mkdir -p /var/run/openvswitch …...
一以贯之:从城市网络到“城市一张网”
《论语里仁》中子曰:“参乎,吾道一以贯之”。 孔子所说的“一以贯之”,逐渐成为了中国文化与哲学的重要组成部分,指明事物发展往往需要以标准化、集约化、融合化作为目标。这种智慧在数字化发展中格外重要。从云计算、大数据技术模…...
【Java校招面试】基础知识(四)——JVM
目录 前言一、基础概念二、反射三、类加载器ClassLoader四、JVM内存模型后记 前言 本篇主要介绍Java虚拟机——JVM的相关内容。 “基础知识”是本专栏的第一个部分,本篇博文是第四篇博文,如有需要,可: 点击这里,返回…...
项目管理-计算专题(三点估算、PERT估算)
基本概念 通过考虑估算中的不确定性和风险,可以提高活动持续时间估算的准确性。这个概念源自计划评审技术(PERT)。PERT使用三种估算值来界定活动持续时间的近似区间: 最可能时间(tM):基于最可能获得的资源、最可能取得的资源生产率、对资源可用时间的现…...
【华为OD机试 2023最新 】模拟商场优惠打折(C语言题解 100%)
文章目录 题目描述输入描述输出描述用例题目解析代码思路C语言题目描述 模拟商场优惠打折,有三种优惠券可以用,满减券、打折券和无门槛券。 满减券:满100减10,满200减20,满300减30,满400减40,以此类推不限制使用; 打折券:固定折扣92折,且打折之后向下取整,每次购…...
使用TrieTree(字典树)来实现敏感词过滤
使用TrieTree(字典树)来实现敏感词过滤 1. 字典树定义 字典树(TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。…...
USB转串口芯片CH9101U
CH9101是一个USB总线的转接芯片,实现USB转异步串口。提供了常用的MODEM联络信号,用于为计算机扩展异步串口,或者将普通的串口设备或者MCU直接升级到USB总线。 特点 全速USB设备接口,兼容USB V2.0。内置固件,仿真标准串…...
定制网站制作报价/百度seo快速排名优化服务
1. JNA简单介绍先说JNI(Java Native Interface)吧,有过不同语言间通信经历的一般都知道,它允许Java代码和其他语言(尤其C/C)写的代码进行交互,只要遵守调用约定即可。首先看下JNI调用C/C的过程,注意写程序时自下而上,调…...
帝国cms做门户网站/百度电脑端网页版入口
在CMakeLisits.txt里面指定编译的ARM 代码目录和DSP上代码的目录和DSP的目录,以及IDL文件的目录(制定会放到DSP上执行的函数名字) #ifndef EXAMPLE_INTERFACE_IDL #define EXAMPLE_INTERFACE_IDL #include "AEEStdDef.idl" in…...
wordpress分页目录编辑/互动营销名词解释
首先, equality 等同, identity 恒等。, 两边值类型不同的时候,要先进行类型转换,再比较。,不做类型转换,类型不同的一定不等。下面分别说明:先说 ,这个比较简单。下面的…...
可以做简历的网站/厦门推广平台较好的
http://www.franche-comte.org/mini-site/cn/french-travel-castel-cheese-wine.html 转载于:https://www.cnblogs.com/gaozehua/archive/2011/09/07/2169764.html...
微网站建设开发/上海seo搜索优化
这是一个iPhone Menu JSON文件的示例,您可能会看到该文件用于存储菜单配置设置以在移动设备上设置网站。 使用简单的JSON格式,可以轻松地在移动和Web组件之间共享它。 另外: 请参阅更多JSON示例。 {"menu": {"header": &…...