美文网首页
IOS 国际化词条 Python3 脚本

IOS 国际化词条 Python3 脚本

作者: 阳光下的灰尘 | 来源:发表于2023-08-02 14:17 被阅读0次

    一、词条处理脚本---使用教程

    (1)环境篇

    1: 该脚本基于python3 环境,请确保你的mac 安装了python3
    2: 包依赖,请在python3环境下安装 xlrd;

    pip3 install xlrd
    

    (2)使用篇

    1: 桌面创建一个文件夹, 例如 wordEntry,将该脚本文件与下载的最新的 ’词条.xlsx‘ excel文件 放置于该新文件夹下
    2:执行 脚本

    python3 wordEntry.py
    

    注意:请确保每次只有一个 excell 文件与脚本同处一个目录下

    自动帮忙修改xcode工程中的国际化文件
    要求:
    <1>需要在中、英文、繁体等国际化文件中加上分隔符,脚本将以分隔符做区分,分隔符之后的词条都将会被从excel中读取的新词条覆盖
    <2>分隔符,目前定义为 <script/beginCoverage>

    eg:
    修改前:
    //Demo 第一期20190703---------------------------Demo-------
    "hello" = "欢迎您";
    **
    添加分隔符后:
    //Demo 第一期20190703---------------------------Demo-------
    //<script/beginCoverage>
    "hello" = "欢迎您";
    **

    <3> "hello" = "欢迎您"; 及以后的内容都将被覆盖

    <4> 脚本的执行方式有所改变

    python3 wordEntry.py project_path(xcode项目的根目录)
    eg:
    python3 wordEntry.py ~/Desktop/Demo

    <5> 当然你也可以不添加项目路径,仍然使用python3 wordEntry.py去执行, 但需要修改脚本开头的 project_path = '/Users/admin/Desktop/wallet' 成自己对应项目的路径,(注意:脚本优先读取您传入的项目路径)

    比如修改为-> project_path = '/Users/***/Desktop/Demo'

    词条脚本报错:
    xlrd.biffh.XLRDError: Excel xlsx file; not supported
    需要执一下一下命令:
    pip3 install xlrd==1.2.0

    解析:https://blog.csdn.net/weixin_45579026/article/details/112601560

    二、IOS 国际化词条 Python3 脚本

    import sys
    import os
    import xlrd
    
    
    #----------------------------参数配置----------------------
    #项目地址
    project_path = '/Users/***/Desktop/Demo_ios/Demo'
    #excel中sheetname的数组
    excel_sheetNames = [
    'Demo',
    ]
    
    
    # 在国际化文件中写的分隔符,需要保持一致
    separator_chars = [
    '<script/Demo/beginCoverage>',
    ]
    
    
    
    #说明: sheetname的个数与分隔符的个数需要保持一致,并且顺序一一对应
    #----------------------------参数配置 end----------------------
    
    
    #打印
    def print_debug(*argus):
        # print('***')
        print('-->', *argus)
    
    
    # 字符串中是否包含中文文字
    def is_Chinese(world):
        isCh = False
        for ch in world:
            if '\u4e00' <= ch <= '\u9fff':
                isCh = True
                break
        return isCh
    
    #查找excel,返回路径
    def findExcel(path=None):
        print_debug('开始查找Excel文件...')
        if path == None:
            path = "."
        # 1:以 ‘.’ 开头的是隐藏文件,剔除,否则读取会报错,2:必须是excel
        excelList = [x for x in os.listdir(
            '.') if x[0] != '.' and os.path.splitext(x)[1] == '.xlsx']
        if excelList != None:
            #从找到的excel数组中,返回第一个
            print_debug('找到Excel文件,name=', excelList[0])
            return excelList[0]
    
    
    # 读取excel内容--按照excel sheet_name
    def readExcelDataBySheetName(filePath, sheetName=None):
        print_debug('开始读取excel= "%s",sheetName="%s"'%(filePath, sheetName))
        if filePath == None or sheetName == None:
            print_debug('参数异常!')
            return
        wb = xlrd.open_workbook(filePath)
        sheet1 = wb.sheet_by_name(sheetName)
        col1_code = sheet1.col_values(3) # // 语言Key, 要注意第几列
        col2_cn = sheet1.col_values(4) # // 语言Value, 要注意第几列
        col3_ct = sheet1.col_values(5) # // 语言Value, 要注意第几列
    #    col4_en = sheet1.col_values(6) # // 新语言Value, 要注意第几列
        shouldJumpFirstRow = is_Chinese(col1_code[0]) # // 第一行 标题去掉
        shouldJumpFirstRow = True
        if shouldJumpFirstRow:
            print_debug('warning: 第一行数据不合法,删除...', col1_code[0])
            col1_code.pop(0) # // 第一行 标题去掉
            col2_cn.pop(0) # // 第一行 标题去掉
            col3_ct.pop(0) # // 第一行 标题去掉
    #        col4_en.pop(0) # // 第一行 标题去掉
        # 返回元组 (code, 简体中文, 繁体中文, 英文)
        col2_cn = transferIfNeedForValues(col2_cn) # // 语言Value, 要注意第几列
        col3_ct = transferIfNeedForValues(col3_ct) # // 语言Value, 要注意第几列
    #    col4_en = transferIfNeedForValues(col4_en) # // 新语言Value, 要注意第几列
        print_debug('数据分析完成! sheetName=', sheetName)
        return (col1_code, col2_cn, col3_ct) # // 新语言注意
    # 读取excel内容--按照excel sheet_index
    def readExcelDataBySheetIndex(filePath, sheetIndex=None):
        print_debug('开始读取excel= "%s",sheetIndex="%s"'%(filePath, sheetIndex))
        if filePath == None or sheetIndex == None:
            print_debug('参数异常!')
            return
        wb = xlrd.open_workbook(filePath)
        sheet1 = wb.sheet_by_index(sheetIndex)
        col1_code = sheet1.col_values(3) # // 语言key, 要注意第几列
        col2_cn = sheet1.col_values(4) # // 语言Value, 要注意第几列
        col3_ct = sheet1.col_values(5) # // 语言Value, 要注意第几列
    #    col4_en = sheet1.col_values(6) // 新语言要注意
        shouldJumpFirstRow = is_Chinese(col1_code[0])
        shouldJumpFirstRow = True
        if shouldJumpFirstRow:
            print_debug('warning: 第一行数据不合法,删除...', col1_code[0])
            col1_code.pop(0)
            col2_cn.pop(0)
            col3_ct.pop(0)
            col4_en.pop(0)
        # 返回元组 (code, 简体中文, 繁体中文, 英文)
        col2_cn = transferIfNeedForValues(col2_cn)
        col3_ct = transferIfNeedForValues(col3_ct)
    #    col4_en = transferIfNeedForValues(col4_en)  // 新语言要注意
        print_debug('数据分析完成! sheetIndex=', sheetIndex)
        return (col1_code, col2_cn, col3_ct) # // 新语言要注意
        
    
    #将内容写入指定的文件路径
    def writeDataToFile(keys, values, destination_path):
        print_debug('开始准备写入数据...')
        if keys == None or values == None or len(keys) != len(values) or destination_path == None:
            return
        # if os.path.exists(destination_path) == False:
        #   os.mkdir(destination_path)
        print_debug('写入路径为:' + destination_path)
        resultMap = {}
        for x in range(0, len(keys)):
            if len(keys[x]) == 0 or len(values[x]) == 0:
                # 有key为空或者value为空串儿,跳过不计
                continue
            resultMap[keys[x]] = values[x]
        file_write(destination_path, resultMap)
        print_debug('数据写入完成!')
    
    #文件写入
    def file_write(full_path, dic_data):
        if full_path == None:
            print_debug('error: 写入路径为空!')
            return
        if os.path.exists(full_path):
            print_debug('删除旧的strings文件')
            os.remove(full_path)
        for key, value in dic_data.items():
            if len(key) == 0 or len(value) == 0:
                # 空字符串不写入,跳过
                continue
            try:
                # value = transferIfNeed(value)
                content = '"{key}" = "{value}";'.format(key=key, value=value)
                open(full_path, 'a', encoding='utf-8').write('\n' + content)
            except Exception as e:
                print_debug('error: 写入出错!!!!!')
                print_debug(e)
    
    
    # 转义---单一字符串转义--如果包含了双引号 ' " '
    def transferIfNeed(value):
        if r'"' in value:
            # 把字符串拆分了,一个一个的去比较
            allChars = [x for x in value]
            # print_debug('allChars.count = ', len(allChars))
            results = []
            for x in range(len(allChars)):
                sub = value[x]
                # 如果 " 存在,并且引号前一个字符它不是 \ , 则将 " 修改成 \"
                if sub == r'"':
                    if x == 0:
                        sub = r'\"'
                    elif value[x - 1] != '\\':
                        sub = r'\"'
                results.append(sub)
            tmp = ''
            # 把处理后的字符串,拼接起来
            for x in results:
                tmp += x
            if len(tmp) != len(value):
                print_debug('发现value 中包含未转义的引号: \n', value)
                value = tmp
                print_debug('开始转义...结果:\n', value)
        return value
    
    
    # 转义- 对数组
    def transferIfNeedForValues(values):
        results = []
        print_debug('对数组进行转义判断')
        if type(values) == list:
            for x in values:
                x = transferIfNeed(x)
                results.append(x)
            print_debug("数组转义完成")
        return results
    
    
    # 查找 Xcode 工程的项目文件地址
    def findProjectPath():
        global project_path
        if len(sys.argv) > 1:
            print_debug("开始查找国际化文件")
            return sys.argv[1]
        elif len(project_path) > 0:
            return project_path
    
    # 在xcode项目中查找指定类型的国际化文件的地址(通过国际化文件的子目录路径)
    def findLocalizable(project_path, subpath):
        if project_path == None:
            print_debug('请提供xcode项目根路径')
            return
        all_files = []
        all_files.append(project_path)
        result = None
        while len(all_files) > 0:
            path = all_files.pop(0)
            if os.path.isdir(path):
                for x in os.listdir(path):
                    all_files.append(os.path.join(path, x))
            elif subpath in path and 'Localizable.strings' in path:
                result = path
        print_debug('找到国际化文件: ', result)
        return result
    
    # 覆盖更新国际化文件的内容
    def coverDataPlus(lprojPath, splitOldDatas, newDataDic, curSepareCharIdx):
        if lprojPath == None or len(splitOldDatas) == 0 or len(newDataDic) == 0 or curSepareCharIdx == None or curSepareCharIdx + 1 >= len(splitOldDatas):
            print_debug("参数错误!")
            return
        replaceIdx = (curSepareCharIdx + 1)*2
        if replaceIdx <= 0:
            replaceIdx = 0
        newData = []
        for (key, value) in newDataDic.items():
            line = '"{key}" = "{value}";\n'.format(key= key, value= value)
            newData.append(line)
        if replaceIdx < len(splitOldDatas):
            splitOldDatas.pop(replaceIdx)
            splitOldDatas.insert(replaceIdx, newData)
        all_lines = []
        for lines in splitOldDatas:
            for line in lines:
                all_lines.append(line)
            
        try:
            file = open(lprojPath, 'w', encoding='utf-8')
            for line in all_lines:
                file.write(line)
            file.close
            print_debug('国际化文件修改完毕!')
        except Exception as e:
            print_debug('覆盖文件出现异常\n')
            print_debug(e)
    
    #将旧的xcode国际化文件内容读取,按照提供的分隔符,拆分成数组,分隔符单独占一个位置
    def split_lproj(lprojPath,seperaChars=[]):
        if len(seperaChars) == 0:
            print_debug("参数错误!")
            return
        try:
            file = open(lprojPath, 'r', encoding='utf-8')
            lines = file.readlines()
            file.close()
            oldData = []
            tmp = []
            line_pre = ''
            for line in lines:
                isMatch = False
                for seperaChar in seperaChars:
                    #空串的分隔符,咱直接跳过
                    if len(seperaChar) == 0:
                        continue
                    #line 中匹配到分隔符
                    if seperaChar in line:
                        #分隔符单独做一个list保存
                        seperaList = [line]
                        if line_pre.startswith("//"):
                            tmp.remove(line_pre)
                            #保留分隔符及分隔符上面的注释语句
                            seperaList = [line_pre, line]
                        #匹配到分隔符后,将分隔符之前的数据及分隔符保存到数组
                        if len(tmp) != 0:
                            oldData.append(tmp)
                        oldData.append(seperaList)
                        tmp = []
                        isMatch = True
                        break
                if isMatch:
                    continue
                tmp.append(line)
                #这里记录一行为 '上一行'
                line_pre = line
            oldData.append(tmp)
            print_debug('国际化文件分割完毕!')
            return oldData            
    
        except Exception as e:
            print_debug('国际化文件分割出现异常\n')
            print_debug(e)
    
    # 修改xcode工程国际化文件
    def updateXcodeProj(dicts, lprojSubPaths, allSeperaChars, curSeperaCharIdx):
        if len(dicts) == 0 or len(lprojSubPaths) == 0 or len(allSeperaChars) == 0:
            print_debug("参数错误")
            return
        if len(dicts) != len(lprojSubPaths) or curSeperaCharIdx >= len(allSeperaChars):
            print_debug("参数错误")
            return
        project_path = findProjectPath()
        print_debug('开始修改Xcode国际化文件, project_path: ', project_path)
        for x in range(len(dicts)):
            lproj_file_path = findLocalizable(project_path, lprojSubPaths[x])
            oldDatas = split_lproj(lproj_file_path, allSeperaChars)
            coverDataPlus(lproj_file_path, oldDatas, dicts[x], curSeperaCharIdx)
    
    # 将编码数组与中文简体 中文繁体 英文,转换成对应的字典数组
    def transferColDataToList(col_code, col_cn, col_ct):
        if col_code == None or col_cn == None or col_ct == None:
            print_debug("参数错误")
            return
        if len(col_code) == 0 or len(col_cn) == 0 or len(col_ct) == 0:
            print_debug("参数错误")
            return
        if len(col_code) != len(col_cn) != len(col_ct):
            print_debug("参数错误")
            return
        colmap_cn = {}
        colmap_ct = {}
    #    colmap_en = {} // 新语言要注意
        for x in range(len(col_code)):
            colmap_cn[col_code[x]] = col_cn[x]
            colmap_ct[col_code[x]] = col_ct[x]
    #        colmap_en[col_code[x]] = col_en[x] // 新语言要注意
        # 编号 中文简体 中文繁体 英文 // 新语言要注意
        return [colmap_cn, colmap_ct]
    
    def dealWithExcelData(excelFilePath, excelSheetNames=[], separetaChars=[]):
        if excelFilePath == None or len(excelSheetNames) != len(separetaChars) or len(separetaChars) == 0:
            print_debug('参数错误!!!')
            return
        for x in range(len(excelSheetNames)):
            sheetName = excelSheetNames[x]
            #3: 读取excel中的指定sheet的数据
            (col1_code,col1_cn,col1_ct) = readExcelDataBySheetName(excelFilePath, sheetName=sheetName)
            # 4:写入数据
            abspath_path = os.path.split(excelFilePath)[0]
            writeDataToFile(col1_code, col1_cn, os.path.join(
                abspath_path, sheetName+'_en.strings'))   # // 不同语言要注意
            writeDataToFile(col1_code, col1_ct, os.path.join(
                abspath_path, sheetName+'_zh-Hans.strings'))   # // 不同语言要注意
    #        writeDataToFile(col1_code, col1_en, os.path.join(  // 新语言要注意
    #            abspath_path, sheetName+'word_en.strings'))
                
            # 5: 将excel sheet1 和sheet2的数据读取处理 // 新语言要注意
            colmapList_sheet = transferColDataToList(col1_code, col1_cn, col1_ct)
            
            # 6: 修改xcode中的国际化文件  // 不同语言要注意  // 新语言要注意
            updateXcodeProj(dicts=colmapList_sheet, lprojSubPaths=['Supporting Files/en.lproj','Supporting Files/zh-Hans.lproj'], allSeperaChars=separetaChars, curSeperaCharIdx=x)
    
    
    def main():
        print_debug("脚本开始执行...")
        #1: 文件路径=当前脚本文件的路径
        abspath_path = os.path.abspath('.')
        #2: 查找到excel的文件路径
        excelFilePath = findExcel(abspath_path)
        #3: 读取excel中的指定sheet的数据
        global excel_sheetNames
        global separator_chars
        dealWithExcelData(excelFilePath, excel_sheetNames, separator_chars)
        print_debug('执行完毕, done!')
        
    # 开始
    main()
    
    

    相关文章

      网友评论

          本文标题:IOS 国际化词条 Python3 脚本

          本文链接:https://www.haomeiwen.com/subject/vfkppdtx.html