1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| """ excel_to_android_xml.py 把多语言表格转换为 Android values-xx/strings.xml 支持: - 自动识别 key 列 (大小写/空格/隐藏字符) - 转义 &, <, >, ", ' - 自动映射 Android 标准语言目录名 """ import os import argparse import pandas as pd import xml.etree.ElementTree as ET
ANDROID_LOCALE_MAP = { "zh-cn": "values-zh-rCN", "zh": "values-zh", "zh-tw": "values-zh-rTW", "zh-hk": "values-zh-rHK", "en": "values", "default": "values" }
def normalize_col_name(name: str) -> str: """去掉前后空格、统一成小写""" if name is None: return "" return str(name).strip().lower()
def safe_android_string(s: str) -> str: """转义 Android strings.xml 特殊字符""" if pd.isna(s): return "" s = str(s) s = s.replace('&', '&') s = s.replace('<', '<').replace('>', '>') s = s.replace('"', '\\"') s = s.replace("'", "\\'") return s
def get_android_values_dir(locale: str) -> str: """根据语言代码生成 Android 规范的 values-xx 目录""" locale_norm = locale.lower() if locale_norm in ANDROID_LOCALE_MAP: return ANDROID_LOCALE_MAP[locale_norm] else: return f"values-{locale_norm}"
def main(): parser = argparse.ArgumentParser() parser.add_argument("input", help="Excel/CSV 文件路径") parser.add_argument("--out-dir", default="out", help="输出目录") parser.add_argument("--key-col", default="key", help="key 列名(默认 key)") parser.add_argument("--skip-empty", action="store_true", help="跳过空翻译") args = parser.parse_args()
if not os.path.exists(args.input): raise SystemExit(f"文件不存在: {args.input}")
if args.input.lower().endswith((".xls", ".xlsx")): df = pd.read_excel(args.input, dtype=str) else: df = pd.read_csv(args.input, dtype=str)
df = df.fillna("")
df.columns = [normalize_col_name(c) for c in df.columns] key_col_norm = normalize_col_name(args.key_col)
print("表头列名(规范化后):", df.columns.tolist())
if key_col_norm not in df.columns: raise SystemExit(f"未找到 key 列 '{args.key_col}',请检查表头")
locale_cols = [c for c in df.columns if c not in (key_col_norm, "comment")]
os.makedirs(args.out_dir, exist_ok=True)
for locale in locale_cols: kv = {} for _, row in df.iterrows(): key = row[key_col_norm].strip() val = row[locale].strip() if not key: continue if args.skip_empty and val == "": continue kv[key] = safe_android_string(val)
dir_name = get_android_values_dir(locale) full_dir = os.path.join(args.out_dir, dir_name) os.makedirs(full_dir, exist_ok=True) out_file = os.path.join(full_dir, "strings.xml")
root = ET.Element("resources") for k, v in kv.items(): el = ET.SubElement(root, "string", attrib={"name": k}) el.text = v tree = ET.ElementTree(root) tree.write(out_file, encoding="utf-8", xml_declaration=True)
print(f"已生成 {out_file}")
if __name__ == "__main__": main()
|