软件多语言文案脚本自动化方案

news2024/9/30 11:23:15

开发高效提速系列目录

  1. 软件多语言文案脚本自动化方案

软件多语言文案脚本自动化方案

  • 背景
  • 目标
  • 整体方案
    • 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和文案内容对应的复制粘贴,非常耗时耗力且容易出现疲劳性错误。

目前关于多语言文案的管理,有部分公司的项目管理可能还停留在如下流程中:

  1. 文案由开发在项目资源文件中进行维护(如Android的strings.xml、IOS的Localizable.strings、PC云端的XXX.ini ),当需要进行文案翻译时,将文案文件语言.xml文件给到产品经理
    在这里插入图片描述

  2. 由产品经理经过其他操作对文案进行翻译,提供多语言翻译后的excel文档给到软件开发,此时文案Key和文案内容失去关联关系
    在这里插入图片描述

  3. 软件开发根据给到的翻译内容查找到对应的文案Key,然后复制到对应的资源文件中进行文案的更新操作

该流程实现过程中,会出现可能的几点问题:

  1. 在版本开发迭代期间,频繁的文案新增修改,需要开发人员频繁手动对齐文案和Key的关系,费时费力
  2. 每一中语言都需要将操作重复进行一遍,语言种类越多耗时越久且手动复制粘贴中容易出现疲劳性错误

目标

为了方便对文案资源进行统一管理,方便产品、开发、测试对文案内容的统一对齐,应该在已有的翻译excel文档的基础上完善文案,对每条文案新增对应的文案Key,同时采用python脚本方法,实现脚本自动化程序更新文案资源,达到提升文案管理和使用效率提升。该方案可以支持Android、IOS、PC云端项目的。

整体方案

该方案的主要思路是:

  1. 创建好统一管理Android、IOS或PC 云端项目的文案管理excel文件
  2. 根据文案资源Excel文件进行python脚本的编写,达到执行脚本时能生成不同格式的文案资源文件
  3. 当文案资源有更新时,在excel文档中进行更新,执行脚本程序完成文案资源的更新
    在这里插入图片描述

根据思路我将其细分为如下几个细分步骤:

  1. 建立标准化文案管理文件。一般是用excel文件管理
  2. 编写Python脚本开发
  3. Python文件管理与程序触发执行
  4. 项目组内人员职责分配

1. 创建文案资源文件

多语言文案可以放在某个excel文件中进行管理,一般使用公司的办公软件如钉钉或飞书软件中进行管理。文案资源的格式可以一般同产品沟通协商共同制作,符合自己公司产品的需求即可,我这里给出移动端文案sheet和PC 云端sheet模板样式,云端和移动端因文案差异太大,建议不用放在一起。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:多语言的文案翻译根据软件的实际需求进行使用,如软件不支持某种语言如"土耳其语",将其对应列空着即可。

2. python脚本开发

python脚本代码如下

# coding=utf-8
import importlib
import re
import sys
import os
import xlrd2

importlib.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, colToStringsMap
    keyColNum = 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, colToStringsMap
    keyColNum = 3
    colToStringsMap = [(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, colToStringsMap
    keyColNum = 2
    colToStringsMap = [(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是空使用defaultValue
    if value == "&nbsp;":
        value = " "
    if not typeColNum is ANDROID and (value is None or value == ""):
        value = defaultValue

    if 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).value
        typeColValue = table.cell(i, typeColNum).value
        keyColValue = table.cell(i, keyColNum).value
        defaultValue = ""

        # 将一行的各列写入对应的多语言文件
        for (col, strFile) in colToFileMap:
            value = table.cell(i, col).value
            value = formatValue(value)
            if col == colToFileMap[0][0]:
                defaultValue = value

            write_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 *****/

主要修改的是参数为

  1. platformType:资源使用的平台,目前定义有Android、IOS、PC云端
  2. excelPath :excel资源文件的目录地址
  3. outputPath:脚本执行后的生成的输出位置
  4. 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安装配置

在这里插入图片描述

  1. 配置.py运行环境
    在这里插入图片描述
    在这里插入图片描述

  2. 配置脚本执行变量
    对于.py文件,需要动态的更改路径的配置
    在这里插入图片描述

  3. 执行脚本程序
    点击执行脚本程序,python脚本将会自动执行,将excel文件生成res/strings.xml文件
    在这里插入图片描述

3. 异常情况解决

  1. Python ModuleNotFoundError: No module named ‘xlrd‘ 异常
    解决方案
    在这里插入图片描述
    在这里插入图片描述

总结

希望这个python脚本自动化方案能帮助大家,多语言文案资源和pyhton脚本我都放到gitee仓库中了,可以下载使用。欢迎大家提出更好的优化建议。
仓库地址:https://gitee.com/luofaxin/LanguageRes.git


相关链接

  1. 软件多语言文案脚本自动化方案

扩展链接:

  1. 项目开发混淆从初识到理解
  2. 项目开发代码分支管理

博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485614.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中间件漏洞(一)CVE-2013-4547(文件名逻辑漏洞)

目录 1. 了解nginx的工作原理 2. 漏洞原理及举例分析 3. 前端php源码分析 4. 注入思路 5. 漏洞复现 5.1 上传文件并抓包分析 5.2 通过访问文件执行php 注意一点 6. 漏洞修复 1. 了解nginx的工作原理 nginx是以PHP语言为主。像Apache一样&#xff0c;Nginx自身是不支持解…

基于黏菌算法的极限学习机(ELM)回归预测-附代码

基于黏菌算法的极限学习机(ELM)回归预测 文章目录 基于黏菌算法的极限学习机(ELM)回归预测1.极限学习机原理概述2.ELM学习算法3.回归问题数据处理4.基于黏菌算法优化的ELM5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;本文利用黏菌算法对极限学习机进行优化&#xff0c;并…

国民技术N32G430开发笔记(15)- IAP升级 树莓派串口发送数据

IAP升级 树莓派串口发送数据 1、树莓派接入usb转串口模块后&#xff0c;会生成/dev/ttyUSB0节点&#xff0c;因为树莓派内核已经编译usb_serial以及各模块的驱动。 我们直接对ttyUSB0节点编程即可。 2、协议同上一节 cmd data_lenght data0 … datax checksum 1、获取版本…

AutoDL-GPU租用平台使用(LLM 备用)

网址&#xff1a;AutoDL-品质GPU租用平台-租GPU就上AutoDL 1 打开网址 查看下显卡型号及价格&#xff1a;A100 ( 80 G 显存) 6.68/小时 、4090&#xff08;24G 显存&#xff09;2.68/小时 2 创建实例 1.注册登录后进入控制台&#xff08;页面右上角&#xff09;&#xff0…

08 KVM虚拟机配置-总体介绍

文章目录 08 KVM虚拟机配置-总体介绍8.1 概述8.2 基本格式8.3 配置流程 08 KVM虚拟机配置-总体介绍 8.1 概述 Libvirt工具采用XML格式的文件描述一个虚拟机特征&#xff0c;包括虚拟机名称、CPU、内存、磁盘、网卡、鼠标、键盘等信息。用户可以通过修改配置文件&#xff0c;对…

【应急响应】日志自动提取分析项目ELKLogkitLogonTracerAnolog等

日志自动提取-七牛Logkit&观星应急工具 1、七牛Logkit&#xff1a;(Windows&Linux&Mac等) https://github.com/qiniu/logkit/ 支持的数据源&#xff08;各类日志&#xff0c;各个系统&#xff0c;各个应用等&#xff09; File: 读取文件中的日志数据&#xff0c;包…

第二章 主机规划与磁盘分区

要安装好一部Linux主机并不是那么简单的事情&#xff0c;你必须要针对distributions的特性、服务器软件的能力、未来的升级需求、硬件扩充性需求等等来考虑&#xff0c;还得要知道磁盘分区、文件系统、Linux操作较频繁的目录等等&#xff0c;都得要有一定程度的了解才行。 2.1…

训练CV模型常用的Tips Tricks

训练CV模型常用的Tips & Tricks主要从以下9个方面进行介绍&#xff1a; 图像增强更好的模型学习率和scheduler优化器正则化手段标签平滑知识蒸馏伪标签错误分析 1. 图像增强 以下列出了许多增强方式&#xff0c;有的甚至没见过&#xff0c;但是也不是每一种增强方式都是…

极化码的入门与探索

文章目录 极化码的基础先验知识二进制输入离散无记忆信道模型(Binary-input Discreten Memoryless Channel, B-DMC)二进制离散输入信道的ML判决和错误率B-DMC相关参数的定义和理解 两信道极化N信道极化的解释信道极化分解的蝶形结构补充&#xff1a;生成矩阵的结构 极化码的基础…

Python算法设计 - 快速排序

目录 一、快速排序二、Python算法实现 一、快速排序 快速排序的概念相信大家都能理解&#xff0c;下面这个算法是基于同样想法的另一种算法&#xff0c;其中利用到了分区。如果实施正确&#xff0c;这是一种非常有效的算法&#xff0c;在预期的O(n.log n) 时间内运行&#xff…

性能测试场景分析并设计?超细案例讲解,看这篇就够了

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试场景&…

1.1 基于B/S 结构的 Web 应用

文章目录 1.1 基于B/S 结构的 Web 应用1.2 JDK安装与配置1.3 服务器Tomcat下载与安装1.4 Eclipse安装与使用1.4.1 Eclipse 下载及创建Dynamic Web Project1.4.2 Eclipse 中的编码问题1.4.3 将Tomcat和Eclipse相关联1.4.4 Eclipse 自动部署项目到 Tomcat 的 webapps 目录 1.5 My…

ChatGLM-6B模型微调实战(以 ADGEN (广告生成) 数据集为例)

1 介绍 对于 ChatGLM-6B 模型基于 P-Tuning v2 的微调。P-Tuning v2 将需要微调的参数量减少到原来的 0.1%&#xff0c;再通过模型量化、Gradient Checkpoint 等方法&#xff0c;差不多需要 7GB或则8GB 显存即可运行。 2 环境 2.1 python 环境 conda create -n py310_cha…

go 打包文件夹成zip文件

go 打包文件夹成zip文件 代码有些乱&#xff0c;找不到合适的例子&#xff0c;和优雅的代码 当前代码打包文件是在 需要打包的目录下&#xff0c;测试的时候注意文件翻倍容量 writer, err : zzip.CreateHeader(header) //这里创建文件时注意不要用完整路径 zip中会生产完整路径…

【51单片机】蜂鸣器

&#x1f38a;专栏【51单片机】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【Love Story】 大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; &#x1f354;效果 &#xff08;注意听声音哦&#xff09; 按…

Blob File

文章目录 学习链接Blob创建演示 分片演示 Fileinput手动拖拽fetch 从后端获取流前端代码后端代码 window.showOpenFilePicker Filereader示例1示例2 ArrayBuffer创建bufferTypedArray读写bufferDataView读写buffer与Blob对比 Blob Url & DataUrl示例1示例2 学习链接 Blog …

WIFI密码hacking学习

1 wifite sudo -i 切换到root终端&#xff0c;执行wifite CtrlC 停止WIFI列表扫描 这里选择爆破目标1&#xff0c;他会先监听客户端和wifi的连接的数据包&#xff0c;然后用wordlist-probable.txt里面的字典进行爆破 区别 WPS 是 no 的和yes no会自动化爆破 这种模式默认下…

软件测试行业前景怎么样

软件测试工程师工作好找&#xff0c;但是企业有时却很难招聘到合适的软件测试工程师&#xff0c;这是因为现在企业需要的是自动化测试人才和测试开发人才&#xff01;前些年的手动测试员早已不能满足企业现在的发展需求。 随着人工智能时代的到来&#xff0c;IT行业受到了越来…

从‘孔乙己长衫’现象看社会不公

孔乙已是鲁迅笔下人物&#xff0c;穷困流倒还穿着象征读书人的长衫&#xff0c;迁腐、麻木。最近&#xff0c;大家自我调佩是“当代孔乙己”&#xff0c;学历成为思想负担&#xff0c;找工作时高不成低不就。 认识孔乙己 孔乙己是清朝末年的小贩&#xff0c;生活在贫苦的阶层…

ubuntu22.04安装与配置

目录 一、环境及下载 iso下载 VM配置 二、虚拟机与环境配置 虚拟机开始后的配置 一些工具配置 参考&#xff1a; VMware Workstation Pro 文档 一、环境及下载 iso下载 Download Ubuntu Desktop | Download | Ubuntu 新出了23但是偶数年份稳定支持&#xff0c;所以我…