先日リリースした FlickAddress では日中英、3つの言語に対応しています。日英くらいだとチーム内で大体翻訳できるわけですが、中国語となるとチーム内で処理できず、翻訳者の方とやり取りが発生します。するとやり取りの為の中間ファイルを作ったり等、時間がかかって仕方ありません。また日中英だけでも十分大変なのに、さらに多くの言語に対応するとなると、個々の Localizabl.strings を管理していくのでは話になりません。そこで Localizable.strings と CSV を相互に変換するスクリプトを書いてみました。
手順は以下の通りです。
- まず各言語用の Localizable.strings を作成
- 次に1つの言語分だけ Localizable.strings を記述
- 以下のようにスクリプトを実行
ここでは Resources ディレクトリ以下に各 lproj が存在している事を想定しています。またスクリプトが少し長くなったのでエントリの末尾に張っておきます。
$ python ls2csv.py tocsv Resources
そうすると以下のような CSV ファイルが生成されます。一番左に Localizable.strings に定義されているキーの一覧が、続いて各言語のカラムが生成されています。CSV ファイルなら翻訳者の方とのやり取りも簡単ですね。
後は CSV ファイルに必要な翻訳データを入力して、Localizable.strings に再変換を行います。以下のコマンドを実行すると入力された CSV を元に言語毎の Localizable.strings が生成されますので、上書きするなりコピペするなりして使って下さい。
$ python ls2csv.py tols data.csv
これで iPhone アプリを多言語化するのが少しは楽になるのではと思います。「あぁ、めんどくさい」、そう思ったら少し時間を取って効率化。そんな心の余裕を日々持ちたいものですね。
スクリプト本体は例によって Python です。
#!/usr/bin/python # -*- coding: utf-8 -*- import sys import os import re def ls2csv(ls_dir): langs = [] section_data = {'No Section':{}} all_data = [] # get lang list res_dir = os.getcwd() if not os.path.exists(ls_dir): print "指定されたディレクトリ(%s)は存在しません。" % (ls_dir) sys.exit(0) res_dir = os.path.join(res_dir, ls_dir) for (root, dirs, files) in os.walk(res_dir): for filename in dirs: (basename, ext) = os.path.splitext(filename) if ext.lower() == '.lproj': langs.append(basename) # get key list key_val_regex = re.compile('"(?P.+)"s+=s+"(?P .+)";') section_regex = re.compile('//s+(?P .+)') first_lang = True current_section_name = None for lang in langs: lang_res_file = os.path.join(res_dir, '%s.lproj/Localizable.strings' % (lang,)) content = open(lang_res_file, 'r').read() for line in content.split('n'): m = section_regex.match(line) if m: current_section_name = m.group('section_name') if first_lang: if current_section not in section_data.keys(): section_data[current_section_name] = {} all_data.append({'section_name':current_section_name, 'section_data':section_data[current_section_name]}) if not current_section_name or current_section_name not in section_data.keys(): current_section_name = 'No Section' current_section = section_data[current_section_name] m = key_val_regex.match(line) if m: key = m.group('key') val = m.group('val') found = False if key not in current_section: for section_name in section_data.keys(): section = section_data[section_name] if key in section: section[key][lang] = val found = True break if not found: if key not in current_section: current_section[key] = {} current_section[key][lang] = val first_lang = False all_data.append({'section_name':'No Section', 'section_data':section_data['No Section']}) # output csv csv = 'key,' for i, lang in enumerate(langs): csv += lang if i < len(langs) - 1: csv += ',' csv += 'n' for section in all_data: csv += '// %sn' % (section['section_name']) for key in section['section_data'].keys(): csv += '%s,' % (key,) for i, lang in enumerate(langs): try: val = section['section_data'][key][lang] except: val = '' csv += val if i < len(langs) - 1: csv += ',' csv += 'n' csv += 'n' print csv def csv2ls(csv_file): csv_data = open(csv_file, 'r').read().split('n') head_line = csv_data[0] langs = [lang.replace('"', '') for lang in head_line.split(',')[1:]] all_data = {} for lang in langs: all_data[lang] = [] # get all sections current_section_name = None for line in csv_data[1:]: params = line.split(',') if len(params) != len(langs) + 1: current_section_name = line for lang in langs: all_data[lang].append({'section_name':current_section_name, 'section_data':{}}) else: key = params[0] for i, lang in enumerate(langs): val = params[i + 1] section_data = all_data[lang][-1]['section_data'] section_data[key] = val # output for lang_name in all_data: lang_name = lang_name.replace('"', '') lang_data = all_data[lang_name] result = '' for section in lang_data: result += '%sn' % (section['section_name'].replace('"', '')) for key, value in section['section_data'].items(): key = key.replace('"', '') value = value.replace('"', '') result += '"%(key)s" = "%(val)s";n' % {'key':key, 'val':value} f = open('%s.strings' % (lang_name,), 'w') f.write(result) f.close() def printUsageAndExit(): print '''Usage: ls2csv.py tocsv [target_dir] ls2csv.py tols [csv_file] ''' sys.exit(0) if __name__ == '__main__': if len(sys.argv) < 3: printUsageAndExit() command = sys.argv[1] if command == 'tocsv': ls2csv(sys.argv[2]) elif command == 'tols': csv2ls(sys.argv[2]) else: printUsageAndExit()