IOS 國際化詞條 Python3 腳本

一某饰、詞條處理腳本---使用教程

(1)環(huán)境篇

1: 該腳本基于python3 環(huán)境透硝,請確保你的mac 安裝了python3
2: 包依賴吗坚,請在python3環(huán)境下安裝 xlrd;

pip3 install xlrd

(2)使用篇

1: 桌面創(chuàng)建一個文件夾, 例如 wordEntry,將該腳本文件與下載的最新的 ’詞條.xlsx‘ excel文件 放置于該新文件夾下
2:執(zhí)行 腳本

python3 wordEntry.py

注意:請確保每次只有一個 excell 文件與腳本同處一個目錄下

自動幫忙修改xcode工程中的國際化文件
要求:
<1>需要在中甫菠、英文锰霜、繁體等國際化文件中加上分隔符,腳本將以分隔符做區(qū)分示姿,分隔符之后的詞條都將會被從excel中讀取的新詞條覆蓋
<2>分隔符甜橱,目前定義為 <script/beginCoverage>

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

<3> "hello" = "歡迎您"; 及以后的內(nèi)容都將被覆蓋

<4> 腳本的執(zhí)行方式有所改變

python3 wordEntry.py project_path(xcode項(xiàng)目的根目錄)
eg:
python3 wordEntry.py ~/Desktop/Demo

<5> 當(dāng)然你也可以不添加項(xiàng)目路徑,仍然使用python3 wordEntry.py去執(zhí)行, 但需要修改腳本開頭的 project_path = '/Users/admin/Desktop/wallet' 成自己對應(yīng)項(xiàng)目的路徑峻凫,(注意:腳本優(yōu)先讀取您傳入的項(xiàng)目路徑)

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

詞條腳本報錯:
xlrd.biffh.XLRDError: Excel xlsx file; not supported
需要執(zhí)一下一下命令:
pip3 install xlrd==1.2.0

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

二渗鬼、IOS 國際化詞條 Python3 腳本

import sys
import os
import xlrd


#----------------------------參數(shù)配置----------------------
#項(xiàng)目地址
project_path = '/Users/***/Desktop/Demo_ios/Demo'
#excel中sheetname的數(shù)組
excel_sheetNames = [
'Demo',
]


# 在國際化文件中寫的分隔符,需要保持一致
separator_chars = [
'<script/Demo/beginCoverage>',
]



#說明: sheetname的個數(shù)與分隔符的個數(shù)需要保持一致荧琼,并且順序一一對應(yīng)
#----------------------------參數(shù)配置 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數(shù)組中,返回第一個
        print_debug('找到Excel文件,name=', excelList[0])
        return excelList[0]


# 讀取excel內(nèi)容--按照excel sheet_name
def readExcelDataBySheetName(filePath, sheetName=None):
    print_debug('開始讀取excel= "%s",sheetName="%s"'%(filePath, sheetName))
    if filePath == None or sheetName == None:
        print_debug('參數(shù)異常!')
        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]) # // 第一行 標(biāo)題去掉
    shouldJumpFirstRow = True
    if shouldJumpFirstRow:
        print_debug('warning: 第一行數(shù)據(jù)不合法脐恩,刪除...', col1_code[0])
        col1_code.pop(0) # // 第一行 標(biāo)題去掉
        col2_cn.pop(0) # // 第一行 標(biāo)題去掉
        col3_ct.pop(0) # // 第一行 標(biāo)題去掉
#        col4_en.pop(0) # // 第一行 標(biāo)題去掉
    # 返回元組 (code镐侯, 簡體中文, 繁體中文驶冒, 英文)
    col2_cn = transferIfNeedForValues(col2_cn) # // 語言Value, 要注意第幾列
    col3_ct = transferIfNeedForValues(col3_ct) # // 語言Value, 要注意第幾列
#    col4_en = transferIfNeedForValues(col4_en) # // 新語言Value, 要注意第幾列
    print_debug('數(shù)據(jù)分析完成! sheetName=', sheetName)
    return (col1_code, col2_cn, col3_ct) # // 新語言注意
# 讀取excel內(nèi)容--按照excel sheet_index
def readExcelDataBySheetIndex(filePath, sheetIndex=None):
    print_debug('開始讀取excel= "%s",sheetIndex="%s"'%(filePath, sheetIndex))
    if filePath == None or sheetIndex == None:
        print_debug('參數(shù)異常!')
        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: 第一行數(shù)據(jù)不合法苟翻,刪除...', 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('數(shù)據(jù)分析完成! sheetIndex=', sheetIndex)
    return (col1_code, col2_cn, col3_ct) # // 新語言要注意
    

#將內(nèi)容寫入指定的文件路徑
def writeDataToFile(keys, values, destination_path):
    print_debug('開始準(zhǔn)備寫入數(shù)據(jù)...')
    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('數(shù)據(jù)寫入完成!')

#文件寫入
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)


# 轉(zhuǎn)義---單一字符串轉(zhuǎn)義--如果包含了雙引號 ' " '
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('發(fā)現(xiàn)value 中包含未轉(zhuǎn)義的引號: \n', value)
            value = tmp
            print_debug('開始轉(zhuǎn)義...結(jié)果:\n', value)
    return value


# 轉(zhuǎn)義- 對數(shù)組
def transferIfNeedForValues(values):
    results = []
    print_debug('對數(shù)組進(jìn)行轉(zhuǎn)義判斷')
    if type(values) == list:
        for x in values:
            x = transferIfNeed(x)
            results.append(x)
        print_debug("數(shù)組轉(zhuǎn)義完成")
    return results


# 查找 Xcode 工程的項(xiàng)目文件地址
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項(xiàng)目中查找指定類型的國際化文件的地址(通過國際化文件的子目錄路徑)
def findLocalizable(project_path, subpath):
    if project_path == None:
        print_debug('請?zhí)峁﹛code項(xiàng)目根路徑')
        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

# 覆蓋更新國際化文件的內(nèi)容
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("參數(shù)錯誤!")
        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('覆蓋文件出現(xiàn)異常\n')
        print_debug(e)

#將舊的xcode國際化文件內(nèi)容讀取涕烧,按照提供的分隔符月而,拆分成數(shù)組,分隔符單獨(dú)占一個位置
def split_lproj(lprojPath,seperaChars=[]):
    if len(seperaChars) == 0:
        print_debug("參數(shù)錯誤!")
        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:
                    #分隔符單獨(dú)做一個list保存
                    seperaList = [line]
                    if line_pre.startswith("http://"):
                        tmp.remove(line_pre)
                        #保留分隔符及分隔符上面的注釋語句
                        seperaList = [line_pre, line]
                    #匹配到分隔符后父款,將分隔符之前的數(shù)據(jù)及分隔符保存到數(shù)組
                    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('國際化文件分割出現(xiàn)異常\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("參數(shù)錯誤")
        return
    if len(dicts) != len(lprojSubPaths) or curSeperaCharIdx >= len(allSeperaChars):
        print_debug("參數(shù)錯誤")
        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)

# 將編碼數(shù)組與中文簡體 中文繁體 英文,轉(zhuǎn)換成對應(yīng)的字典數(shù)組
def transferColDataToList(col_code, col_cn, col_ct):
    if col_code == None or col_cn == None or col_ct == None:
        print_debug("參數(shù)錯誤")
        return
    if len(col_code) == 0 or len(col_cn) == 0 or len(col_ct) == 0:
        print_debug("參數(shù)錯誤")
        return
    if len(col_code) != len(col_cn) != len(col_ct):
        print_debug("參數(shù)錯誤")
        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('參數(shù)錯誤!!!')
        return
    for x in range(len(excelSheetNames)):
        sheetName = excelSheetNames[x]
        #3: 讀取excel中的指定sheet的數(shù)據(jù)
        (col1_code,col1_cn,col1_ct) = readExcelDataBySheetName(excelFilePath, sheetName=sheetName)
        # 4:寫入數(shù)據(jù)
        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的數(shù)據(jù)讀取處理 // 新語言要注意
        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("腳本開始執(zhí)行...")
    #1: 文件路徑=當(dāng)前腳本文件的路徑
    abspath_path = os.path.abspath('.')
    #2: 查找到excel的文件路徑
    excelFilePath = findExcel(abspath_path)
    #3: 讀取excel中的指定sheet的數(shù)據(jù)
    global excel_sheetNames
    global separator_chars
    dealWithExcelData(excelFilePath, excel_sheetNames, separator_chars)
    print_debug('執(zhí)行完畢, done!')
    
# 開始
main()

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痹扇,一起剝皮案震驚了整個濱河市铛漓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鲫构,老刑警劉巖浓恶,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異结笨,居然都是意外死亡包晰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門炕吸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伐憾,“玉大人,你說我怎么就攤上這事赫模∈魉啵” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵瀑罗,是天一觀的道長胸嘴。 經(jīng)常有香客問我,道長斩祭,這世上最難降的妖魔是什么劣像? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮摧玫,結(jié)果婚禮上耳奕,老公的妹妹穿的比我還像新娘。我一直安慰自己诬像,他們只是感情好屋群,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坏挠,像睡著了一般芍躏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上癞揉,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼喊熟。 笑死柏肪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芥牌。 我是一名探鬼主播烦味,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼壁拉!你這毒婦竟也來了谬俄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤弃理,失蹤者是張志新(化名)和其女友劉穎溃论,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痘昌,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钥勋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了辆苔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片算灸。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖驻啤,靈堂內(nèi)的尸體忽然破棺而出菲驴,到底是詐尸還是另有隱情,我是刑警寧澤骑冗,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布赊瞬,位于F島的核電站,受9級特大地震影響沐旨,放射性物質(zhì)發(fā)生泄漏森逮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一磁携、第九天 我趴在偏房一處隱蔽的房頂上張望褒侧。 院中可真熱鬧,春花似錦谊迄、人聲如沸闷供。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歪脏。三九已至,卻和暖如春粮呢,著一層夾襖步出監(jiān)牢的瞬間婿失,已是汗流浹背钞艇。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豪硅,地道東北人哩照。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像懒浮,于是被迫代替她去往敵國和親飘弧。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容