diff --git a/locale/_locale.py b/locale/_locale.py new file mode 100644 index 00000000..4a2ec2c1 --- /dev/null +++ b/locale/_locale.py @@ -0,0 +1,156 @@ +"""_locale.py + +Functions related to building, initializing, updating, and compiling localization translations. + +Borrowed from RetroArcher. +""" +# standard imports +import argparse +import datetime +import os +import subprocess + +project_name = 'Sunshine' + +script_dir = os.path.dirname(os.path.abspath(__file__)) +root_dir = os.path.dirname(script_dir) +locale_dir = os.path.join(root_dir, 'locale') +project_dir = os.path.join(root_dir, project_name.lower()) + +year = datetime.datetime.now().year + +# retroarcher target locales +target_locales = [ + 'de', # Deutsch + 'en', # English + 'en_GB', # English (United Kingdom) + 'en_US', # English (United States) + 'es', # español + 'fr', # français + 'it', # italiano + 'ru', # русский +] + + +def x_extract(): + """Executes `xgettext extraction` in subprocess.""" + + commands = [ + 'xgettext', + f'--default-domain={project_name.lower()}', + f'--output={os.path.join(locale_dir, project_name.lower() + ".pot")}', + '--language=C++', + '--boost', + '--from-code=utf-8', + '-F', + f'--msgid-bugs-address=github.com/{project_name.lower()}', + f'--copyright-holder={project_name}', + f'--package-name={project_name}', + '--package-version=v0' + ] + + pot_filepath = os.path.join(locale_dir, f'{project_name.lower()}.pot') + + extensions = ['cpp', 'h', 'm', 'mm'] + + # find input files + for root, dirs, files in os.walk(project_dir, topdown=True): + for name in files: + filename = os.path.join(root, name) + extension = filename.rsplit('.', 1)[-1] + if extension in extensions: # append input files + commands.append(filename) + + print(commands) + proc = subprocess.run(args=commands, cwd=root_dir) + + # fix header + body = "" + with open(file=pot_filepath, mode='r') as file: + for line in file.readlines(): + if line != '"Language: \\n"\n': # do not include this line + if line == '# SOME DESCRIPTIVE TITLE.\n': + body += f'# Translations template for {project_name}.\n' + elif line.startswith('#') and 'YEAR' in line: + body += line.replace('YEAR', str(year)) + elif line.startswith('#') and 'PACKAGE' in line: + body += line.replace('PACKAGE', project_name) + else: + body += line + + # rewrite pot file with updated header + with open(file=pot_filepath, mode='w+') as file: + file.write(body) + + +def babel_init(locale_code: str): + """Executes `pybabel init` in subprocess. + + :param locale_code: str - locale code + """ + commands = [ + 'pybabel', + 'init', + '-i', os.path.join(locale_dir, f'{project_name.lower()}.pot'), + '-d', locale_dir, + '-D', project_name.lower(), + '-l', locale_code + ] + + print(commands) + proc = subprocess.run(args=commands, cwd=root_dir) + + +def babel_update(): + """Executes `pybabel update` in subprocess.""" + commands = [ + 'pybabel', + 'update', + '-i', os.path.join(locale_dir, f'{project_name.lower()}.pot'), + '-d', locale_dir, + '-D', project_name.lower(), + '--update-header-comment' + ] + + print(commands) + proc = subprocess.run(args=commands, cwd=root_dir) + + +def babel_compile(): + """Executes `pybabel compile` in subprocess.""" + commands = [ + 'pybabel', + 'compile', + '-d', locale_dir, + '-D', project_name.lower() + ] + + print(commands) + proc = subprocess.run(args=commands, cwd=root_dir) + + +if __name__ == '__main__': + # Set up and gather command line arguments + parser = argparse.ArgumentParser( + description='Script helps update locale_id translations. Translations must be done manually.') + + parser.add_argument('--extract', action='store_true', help='Extract messages from c++ files.') + parser.add_argument('--init', action='store_true', help='Initialize any new locales specified in target locales.') + parser.add_argument('--update', action='store_true', help='Update existing locales.') + parser.add_argument('--compile', action='store_true', help='Compile translated locales.') + + args = parser.parse_args() + + if args.extract: + x_extract() + + if args.init: + for locale_id in target_locales: + if not os.path.isdir(os.path.join(locale_dir, locale_id)): + babel_init(locale_code=locale_id) + + if args.update: + babel_update() + + if args.compile: + babel_compile()