[PATCH 1/2] scripts: Add new translation tool trslt.py

From: Wu XiangCheng
Date: Mon Apr 12 2021 - 03:05:34 EST


Add a new translation tool scripts/trslt.py
For
- translation file help tool
- translation corresponding version control

Signed-off-by: Wu XiangCheng <bobwxc@xxxxxxxx>
---
scripts/trslt.py | 267 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 267 insertions(+)
create mode 100755 scripts/trslt.py

diff --git a/scripts/trslt.py b/scripts/trslt.py
new file mode 100755
index 000000000000..1acc6f2e69f3
--- /dev/null
+++ b/scripts/trslt.py
@@ -0,0 +1,267 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Kernel Documentation Translation File tool
+# Document see: Documentation/doc-guide/trslt.rst
+#
+# Wu XiangCheng <bobwxc@xxxxxxxx>, 2021.
+
+import os
+import argparse
+import subprocess
+
+# global verbose mode flag
+VERBOSE_FLAG = False
+
+# change to source root dir
+def cdpath():
+ # at source ROOT
+ if os.path.isdir("Documentation/translations") and os.path.isfile("MAINTAINERS"):
+ return 0
+ # at Documentation/
+ elif os.path.isdir("translations") and os.path.isfile("../MAINTAINERS"):
+ os.chdir("../")
+ return 0
+ # at Documentation/translation/
+ elif os.path.isdir("zh_CN") and os.path.isfile("../../MAINTAINERS"):
+ os.chdir("../../")
+ return 0
+ # at Documentation/translations/ll_NN/
+ elif os.path.isdir("translations") == False and os.path.isdir("../../translations") and os.path.isfile("../../../MAINTAINERS"):
+ os.chdir("../../../")
+ return 0
+ # anywhere else
+ else:
+ print("ERROR: Please run this script under linux kernel source ROOT dir")
+ return -1
+
+# argv
+def arg():
+ parser = argparse.ArgumentParser(
+ description='Linux Kernel Documentation Translation File Tool')
+ # file path
+ parser.add_argument('file', help="specific file path")
+ # verbose mode
+ parser.add_argument('-v', '--verbose',
+ help="enable verbose mode",
+ action='store_true')
+ # language choose
+ parser.add_argument('-l', '--language',
+ help="choose translation language, default: zh_CN",
+ type=str,
+ choices=["it_IT", "ja_JP", "ko_KR", "zh_CN"],
+ default="zh_CN")
+ # required action group
+ ch = parser.add_mutually_exclusive_group(required=True)
+ # \_ copy
+ ch.add_argument('-c', '--copy',
+ help="copy a origin file to translation directory",
+ action='store_true')
+ # \_ update
+ ch.add_argument('-u', '--update',
+ help="get a translation file's update information",
+ action='store_true')
+
+ argv_ = parser.parse_args()
+
+ # modify global VERBOSE_FLAG
+ if argv_.verbose:
+ global VERBOSE_FLAG
+ VERBOSE_FLAG = True
+ print(argv_)
+
+ return argv_
+
+# get newest commit id of a origin doc file
+def get_newest_commit(fp):
+ cmd = "git log --format=oneline --no-merges "+fp
+ p = subprocess.Popen(cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ errors="replace")
+ log = p.stdout.readline()
+ commit_id = log[:log.find(' ')]
+ return commit_id
+
+# add language special header
+def la_head(fp, la):
+ if la == "zh_CN":
+ cfp = fp[0:14]+"translations/"+la+'/'+fp[14:]
+ r = ".. include:: " + \
+ os.path.relpath(
+ "Documentation/translations/zh_CN/disclaimer-zh_CN.rst",
+ cfp[0:cfp.rfind('/')]) + "\n\n"
+ r += ":Original: "+fp+"\n\n"
+ r += ".. translation_origin_commit: "+get_newest_commit(fp)+"\n\n"
+ r += ":译者: 姓名 EnglishName <email@xxxxxxxxxxx>\n\n"
+ else:
+ r = ":Original: "+fp+"\n\n"
+ r += ".. translation_origin_commit: "+get_newest_commit(fp)+"\n\n"
+ r += ":Translator: Name <email@xxxxxxxxxxx>\n\n"
+
+ return r
+
+# copy mode
+def copy(fp, la):
+ if os.path.isfile(fp) == False:
+ return -2
+
+ if fp.find("/translations/") != fp.rfind("/translations/"):
+ print("WARNING: seems you are copying a file only exist in translations/ dir")
+ return -3
+
+ f = open(fp, 'r')
+ try:
+ first = f.read(2048)
+ except:
+ print("ERROR: can not read file", fp)
+ return -2
+
+ spdx_id = first.find(".. SPDX-License-Identifier: ")
+ if spdx_id != -1:
+ insert_id = first.find('\n', spdx_id)+1
+ first = first[:insert_id]+'\n'+la_head(fp, la)+first[insert_id:]
+ else:
+ first = la_head(fp, la)+first
+
+ if fp[0:14] == "Documentation/":
+ cfp = fp[0:14]+"translations/"+la+'/'+fp[14:]
+
+ if cfp[cfp.rfind('.'):] != ".rst":
+ print("WARNING: this is not a rst file, may cause problems.",
+ "copy will continue, but please \033[31mcheck it!\033[0m")
+
+ cfp_dir = cfp[0:cfp.rfind('/')]
+
+ if not os.path.exists(cfp_dir):
+ os.makedirs(cfp_dir)
+
+ if os.path.isfile(cfp):
+ print("WARNING:\033[31m", cfp,
+ "\033[0mis existing, can not use copy, please try -u/--update!")
+ return -3
+
+ cf = open(cfp, 'w')
+ cf.write(first)
+
+ while True:
+ a = f.read(2048)
+ if a != '':
+ cf.write(a)
+ else:
+ break
+
+ cf.close()
+ print("INFO: \033[32m" + cfp +
+ "\033[0m has been created, please remember to edit it.")
+ else:
+ return -2
+
+ return 0
+
+# generete origin text diff file for update
+def gen_diff(ofp, old_id):
+ new_id = get_newest_commit(ofp)
+ if old_id == new_id:
+ return 1
+
+ cmd = "git show "+old_id+".."+new_id+" "+ofp
+ p = subprocess.Popen(cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ errors="replace")
+ log = p.stdout.read()
+ log = cmd+"\n\n"+log
+ return log
+
+# update mode
+def update(fp, la):
+ if os.path.isfile(fp) == False:
+ return -2
+ if fp.find("Documentation/translations/"+la) == -1:
+ print("ERROR:", fp, "does not belong to", la, "translation!")
+ return -3
+
+ # origin file path
+ ofp = fp[:fp.find("translations/"+la)] + \
+ fp[fp.find("translations/"+la)+14+len(la):]
+
+ if not os.path.isfile(ofp):
+ print("ERROR: origin file",ofp,"does not exist or not a file")
+ return -2
+
+ f = open(fp, 'r')
+ try:
+ first = f.read(3072)
+ except:
+ print("ERROR: can not read file", fp)
+ return -2
+
+ commit_id = first.find("\n.. translation_origin_commit: ")
+ if commit_id == -1:
+ print("WARNING:", fp, "\033[31mdoes not have a translation_origin_commit tag,",
+ "can not generate a diff file\033[0m, please add a tag if you want to update it.")
+ print("\n\033[33m.. translation_origin_commit: " +
+ get_newest_commit(ofp) + "\033[0m")
+ return -4
+ else:
+ commit_id = commit_id+1 # '\n'
+ commit_id = first[commit_id:first.find('\n', commit_id)]
+ commit_id = commit_id[commit_id.find(' ')+1:]
+ commit_id = commit_id[commit_id.find(' ')+1:]
+
+ diff = gen_diff(ofp, commit_id)
+ if diff == 1:
+ print("INFO:", ofp, "does not have any change since", commit_id)
+ else:
+ with open(fp+".diff", 'w') as d:
+ d.write(diff)
+ print("INFO: \033[32m"+fp+".diff\033[0m file has generated",)
+ print("INFO: if you want to update " + fp +
+ ", please \033[31mDo Not Forget\033[0m to update the translation_origin_commit tag.",
+ "\n\n\033[33m.. translation_origin_commit: " +
+ get_newest_commit(ofp) + "\033[0m")
+
+ return 0
+
+# main entry
+def main():
+ argv_ = arg()
+
+ # get file's abspath before cdpath
+ file_path = os.path.abspath(argv_.file)
+ if VERBOSE_FLAG:
+ print(file_path)
+
+ if cdpath() != 0:
+ return -1
+
+ # if file_path valid
+ if file_path.find("Documentation") == -1:
+ print("ERROR: file does not in Linux Kernel source Documentation")
+ return -2
+ elif os.path.isfile(file_path[file_path.find("Documentation"):]) == False:
+ print("ERROR: file does not exist or not a file")
+ return -2
+ else:
+ file_path = file_path[file_path.find("Documentation"):]
+
+ if VERBOSE_FLAG:
+ print(file_path)
+
+ if argv_.copy:
+ return copy(file_path, argv_.language)
+ elif argv_.update:
+ return update(file_path, argv_.language)
+
+ return 0
+
+
+if __name__ == "__main__":
+ exit_code = main()
+ if VERBOSE_FLAG:
+ if exit_code == 0:
+ print("exit with code:\033[32m", exit_code, "\033[0m")
+ else:
+ print("exit with code:\033[31m", exit_code, "\033[0m")
+ exit(exit_code)
--
2.20.1