iOS【语言国际化处理】python脚本读取Excel内容批量导入国际化语言文件中(一)

在项目开发中,偶尔需要新增国际化语言,但是提供的翻译文档一般是Excel文件,
若只是一个,还可以简单一个一个辛苦的复杂,
若内容很多,或新增好几个国际化语言,就要吐....了,
之前用的是工具,现在自己简单实现学习一下,就不工具化了;

这个版本:批量处理读取Excel到txt文件中

下一个版本,
将项目中的国际化语言批量导入到Excel中....

相关国际化处理:
iOS【语言国际化处理】python脚本读取Excel内容批量导入国际化语言文件中(一)
iOS【语言国际化处理】python脚本将国际化语言文件批量导入Excel文件中(二)
iOS【图片国际化处理】python脚本Assets.xcassets图片名称及MD5批量处理(三)

文件示例目录
|--------Language---ar.lproj-------------Localizable.strings----|
|---------------------en.lproj------------Localizable.strings----|
|---------------------es.lproj------------Localizable.strings----|
|---------------------Language.xlsx----------------------------|
Excel结构示意图

Excel第一行内容:key | ar.lproj | en.lproj | es.lproj |
Excel后面行内容:第一列为Key, 后面列为对应语言的翻译

[key]-----[ar.lporj]------[en.lproj]-----[es.lproj]
[key1]----[test_ar]------[test_en]-----[test_es]
[key2]----[test2_ar]----[test2_en]----[test2_es]
Localizable.strings结构示意图
"kTest_1" = "test_ar_1 \n 11";
"kTest_2" = "test_ar_2";
"kTest_3" = "test_ar_3  %@ 33";
文件目录截图
翻译Excel截图
国际化处理截图

Python3, 需要安装xlrd读Excel,xlwt写Excel

python里面的xlrd模块(python3.9)表示对应版本
curl https://bootstrap.pypa.io/get-pip.py | python3.9
pip install xlrd
pip install xlwt
pip install pyexcel-xls

终端使用示例
python3.9 /Users/odd/Documents/Project/测试国际化/TestPython/CCExcelToLocalizationTool.py
配置使用:
print("可以配置调整路径:")
    # 国际化语言文件
    languageFile = "/Users/odd/Documents/Project/测试国际化/Language"
    # 需要国际化的语言文件名
    languageLocalizableName = "Localizable.strings"
    # 打开excel文件读取数据
    languageExcefilePath = "/Users/odd/Documents/Project/测试国际化/Language/Language.xlsx"
    # 添加版本分割注释(可加可不加)
    versionMark = "// ==================== V1.0.0 ==================== //"
    #versionMark = ""
完整脚本:CCExcelToLocalizationTool.py
#-*-coding:utf-8-*-

import xlrd,sys,os

"""读取Excel表格中的数据,写到txt、Localizable.strings中"""

def read_excel_to_txt():

    '''
    # 写入文件路径 示例
    #/Users/odd/Documents/Project/测试国际化/Language/en.lproj/Localizable.txt
    #/Users/odd/Documents/Project/测试国际化/Language/en.lproj/Localizable.strings
    '''

    print("可以配置调整路径:")
    # 国际化语言文件
    languageFile = "/Users/odd/Documents/Project/测试国际化/Language"
    # 需要国际化的语言文件名
    languageLocalizableName = "Localizable.strings"
    # 打开excel文件读取数据
    languageExcefilePath = "/Users/odd/Documents/Project/测试国际化/Language/Language.xlsx"
    # 添加版本分割注释(可加可不加)
    versionMark = "// ==================== V1.0.0 ==================== //"
    #versionMark = ""

    
    # 打开Excel
    languageExceData = xlrd.open_workbook(languageExcefilePath)

    table = languageExceData.sheets()[0] # 表头
    nrows = table.nrows  # 行数
    ncols = table.ncols  # 列数
    
    firstRowDatas = table.row_values(0);
    print(firstRowDatas);

    # 对应语言文件夹
    languageLprojName = ""

    index = 1
    for firtName in firstRowDatas:

        if firtName.upper() == "KEY":
            print("跳过:"+firtName)
            continue
            
        print("\n===========开始写文件=========")
        print("\n===========" + firtName + "===========\n")
        print("开发处理语言文件:" + firtName + " : 第 "+ str(index) + " 个\n")
        
        # 写入文件路径
        languageLprojName = languageFileName(firtName)
        languagePathDir = languageFile+"/"+languageLprojName
        languagePathFile = languageFile+"/"+languageLprojName+"/"+languageLocalizableName

        # 判断文件目录是否存在
        isPathExitsDir(languagePathDir)
        # 判断文件是否存在,不存在,则创建
        isPathExitsFile(languagePathFile)

        #
        # 尽量不要清空处理
        # 若想调整文档顺序一致,可以先清空一次(要确保文档里的,已经存在excel里)
        # clearLocalization(languagePathFile)
        '''
        #1、可以先用CCExcelToLocalizationTool.py:把要导入更新的excel里的文案加入翻译里
        #2、在用CCLocalizationToExcelTool.py:把已经处理的文案导入到excel里
        #3、在调用CCExcelToLocalizationTool.py时,打开清理clearLocalization(languagePathFile)
        '''
        
        # 读取文件内容,格式化处理
        sourceTxtDic = readTxtToDic(languagePathFile)
    
        needWriteMark = isNeedVersionMark(languagePathFile,versionMark)

        #先追加在替换
        sqlfile = open(languagePathFile,"a")
        replateArray = []
        for ronum in range(1, nrows):
            #这行有多少列
            row = table.row_values(ronum)

            #过滤空方式:s.strip()=='',len(s) ==0,s.isspace() == True 
            rowFirstKey = str(row[0]).strip()
            if rowFirstKey == '':
                print("跳过:空数据,第"+str(ronum)+"行")
                continue

            # 将行数据拼接成字符串
            rowValue = handleRowIndexContent(row,index)
            rowKey = str(row[0]).strip()
            # print("======== 行key: "+rowKey)
            if rowKey in sourceTxtDic.keys():
                print("包含:"+rowKey + " 修改value: " + rowValue)
                sourceVlaue = sourceTxtDic[rowKey]
                sourceVlaue["value"] = rowValue
                replateArray.append(sourceVlaue)

            else:
                print("追加:"+rowKey + " value: " + rowValue)
                if versionMark != "" and needWriteMark:
                    print("=========添加分割标识=======")
                    sqlfile.writelines(versionMark + "\r") #将字符串写入新文件
                    needWriteMark = False
                    
                sqlfile.writelines(rowValue + "\r") #将字符串写入新文件
        sqlfile.close() # 关闭写入的文件

        # #替换
        sqlReplacefile = open(languagePathFile,"r+")
        relpaceLines = sqlReplacefile.readlines()

        #print("读取原始txt内容:")
        #print(relpaceLines)
        #print("\n")
        # 序号+内容
        for txtIndex, txtItem in enumerate(relpaceLines):
            #移除 原始内容中行最后默认的\\n,
            txtItem = txtItem.strip('\n')
            relpaceLines[txtIndex] = txtItem
 
        #print("读取去掉\\n换行txt内容:")
        #print(relpaceLines)
        #print("\n")
        
        # 如果向文件写入数据后,不想马上关闭文件,也可以调用文件对象提供的 flush() 函数,它可以实现将缓冲区的数据写入文件中
        for replaceDic in replateArray:
            replaceRow = replaceDic["row"]
            replaceValue = replaceDic["value"]
            print("替换:" + " 行 " + replaceRow + " key: " + replaceDic["key"] + " value: " + replaceValue)
            # 替换需要改变的内容
            relpaceLines[int(replaceRow)] = replaceValue

        sqlWriteFile = open(languagePathFile,"w+")
        #写入对应行+换行
        sqlWriteFile.writelines([tempLine+"\r" for tempLine in relpaceLines])
        sqlWriteFile.close()
        sqlReplacefile.close()

        index = index + 1
    print("\n===========结束写文件=========\n")

 
# 将excel首行的key与其他行分别拼接处理
def handleRowIndexContent(row,index):

    #strip方法用于去除字符串首尾空格
    #效果:"key" = "value";
    values = "\"" +str(row[0]).strip() + "\"" + " = " + "\"" +str(row[index]).strip() + "\"" + ";"
    #print("将excel首行的key与其他行分别拼接处理:\n"+values)
    return values

# en.lproj 文件名处理
def langFieleName(nameString):
    result = ""
    #小写处理
    nameString = nameString.lower()
    
    #方式一:截取 nameString[-5:]  输出右5位:lproj
    # if len(nameString) > 1 :
    #     #获取:en
    #     result = nameString[0:2]
    
    #方式二:分割
    #nameList = nameString.split(".")
    #result = nameList[0]
    
    #方式三:查找截取 变量.find("要查找的内容"[,开始位置,结束位置])
    #lprojIndex = nameString.find('lproj') #3
    #result = nameString[0:lprojIndex]

    #方法四:替换
    result = nameString.replace('.lproj','')

    print(result)
    return result
    
def languageFileName(nameString):
    #小写处理
    result = nameString.lower()
    return result

# 判断目录是否存在,及创建
def isPathExitsDir(dirs):
    if dirs == '':
        print("不是文件目录路径")
        return
    
    if not os.path.exists(dirs):
        print("不存在目录,创建目录")
        os.makedirs(dirs)

# 判断文件是否存在,及创建
def isPathExitsFile(filePath):
    if filePath == '':
        print("不是文件路径")
        return
    if not os.path.exists(filePath):
        #调用系统命令行来创建文件
        os.system(r"touch {}".format(filePath))
    
# 读取iOS国际化语言文件
"""
行样式:"name" = "occc";
rowKey = "name"
rowValue = ""occc";"
row = "0" #第几行

itemDic = {"key":rowKey, "value":rowValue, "row":row}
dic={rowKey=ItemDic}
"""
def readTxtToDic(txtPath):

    #item.endswith('.mp4')
    # line.startswith('#')
    #b = True a = bool(1-b)
    #bool()函数中的1-bool值 就是取bool值的反值了。
    
    if not os.path.exists(txtPath):
        print("读取国际化语言文件不存在")
        return {}

    txtDic = {}
    with open(txtPath,"r") as f:
        txtData = f.readlines()
        # print("\ntxt内容:读取所以内容,并以数组格式返回,会读取到'\\n'")
        #print(txtData)
        #print("\n")
        #['"cancel"="CANCEL11"\n', '"done"="Done222"\n']

        lineIndex = 0
        for line in txtData:
            #移除 \\n
            line = line.strip('\n')
            #print(line)
            #判断以"开头,
            if line.startswith("\""):
                rowDataList = line.split('=')
                
                # key先移除首尾空,在移除"符号
                key = clearTextBeginEnd(rowDataList[0],"\"")
                value = rowDataList[1].strip()
                print("read 行: " + str(lineIndex) + " key: " + key + " value: " + value)
                txtDic[key] = {"key":key,"value":value,"row":str(lineIndex)}

            lineIndex = lineIndex + 1
        f.close()

    #print("字典集合:")
    #print("key==============\n")
    #print(list(txtDic.keys()))
    #print(txtDic)
    return txtDic

# 是否需要添加版本分割标识
def isNeedVersionMark(filePath,versionMark):

    if versionMark == "":
        return False
        
    ishas = True
    with open(filePath,"r") as f:
         txtData = f.readlines()
         for line in txtData:
            # 或 versionMark in line
            if line.find(versionMark) != -1:
                ishas = False
         f.close
    return ishas
    
# 读取txt内容方式
def readeTxtFile(filePath):
    # 一次性读取txt内容
    with open(filePath,"r") as f:
        txtData = f.read()
        print("txt内容:一次性读取")
        print(txtData)
        f.close()

    with open(filePath,"r") as f:
        txtData = f.readline()
        print("txt内容:读取一行")
        print(txtData)
        f.close()

    # with open(filePath,"r") as f:
    #     txtData = f.readlines()
    #     print("txt内容:读取所以内容,并以数组格式返回,会读取到'\\n'")
    #     #print(txtData)
    #     #['"cancel"="CANCEL11"\n', '"done"="Done222"\n']
    #     for line in txtData:
    #         #移除
    #         line = line.strip('\n')
    #         print(line)
    #     f.close()
    


# 写txt文件追加
def writetxt_a(txt,path):
    #f.seek(0):把文件定位到数据起始位置(index=0),
    #若没有这句,文件默认定位到数据结束位置,w.truncate()不起作用
    with codecs.open(path,'a','utf-8') as f:
        f.seek(0)    # 定位
        f.truncate()  # 清空文件
        f.write(txt)
        f.close()

# 清空内容,可以保持顺序一致
def clearLocalization(path):
    # 清空文件内容
    clearTextContent(path)
    #读取txt内容
    #readeTxtFile(path)
        
    
# 清空txt文件内容
def clearTextContent(path):
    # 清空txt文件内容(方式一)
    clearfile = open(path, 'w').close()

    #清空txt文件内容(方式二)
    #with open(path, 'r+') as file:
    #    file.truncate(0)
    #    file.close()
    print("清空文件内容:"+path)

# 清除首尾空和"符号
def clearTextBeginEnd(sourceText,clearChart):
    
    # isinstance(sourceText,str) 是否字符串,然后取反
    if bool(1 - isinstance(sourceText,str)):
        print("清除数据不是字符串")
        return ""

    sourceText = sourceText.strip()
    sourceText = sourceText.strip(clearChart);
    return sourceText
    
# 将excel某行的数据,拼接处理
def strs(row):
    values = "";
    for i in range(len(row)):
        if i == len(row) - 1:
            values = values + str(row[I])
        else:
            values = values + str(row[i]) + ","
    return values

read_excel_to_txt()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容