import glob import io import os import sys from django.conf import settings from django.core.management import CommandError from django.core.management.commands.makemessages import ( Command as MakeMessagesCommand, check_programs, ) from judge.models import NavigationBar, ProblemType class Command(MakeMessagesCommand): def add_arguments(self, parser): parser.add_argument( "--locale", "-l", default=[], dest="locale", action="append", help="Creates or updates the message files for the given locale(s) (e.g. pt_BR). " "Can be used multiple times.", ) parser.add_argument( "--exclude", "-x", default=[], dest="exclude", action="append", help="Locales to exclude. Default is none. Can be used multiple times.", ) parser.add_argument( "--all", "-a", action="store_true", dest="all", default=False, help="Updates the message files for all existing locales.", ) parser.add_argument( "--no-wrap", action="store_true", dest="no_wrap", default=False, help="Don't break long message lines into several lines.", ) parser.add_argument( "--no-obsolete", action="store_true", dest="no_obsolete", default=False, help="Remove obsolete message strings.", ) parser.add_argument( "--keep-pot", action="store_true", dest="keep_pot", default=False, help="Keep .pot file after making messages. Useful when debugging.", ) def handle(self, *args, **options): locale = options.get("locale") exclude = options.get("exclude") self.domain = "dmoj-user" self.verbosity = options.get("verbosity") process_all = options.get("all") # Need to ensure that the i18n framework is enabled if settings.configured: settings.USE_I18N = True else: settings.configure(USE_I18N=True) # Avoid messing with mutable class variables if options.get("no_wrap"): self.msgmerge_options = self.msgmerge_options[:] + ["--no-wrap"] self.msguniq_options = self.msguniq_options[:] + ["--no-wrap"] self.msgattrib_options = self.msgattrib_options[:] + ["--no-wrap"] self.xgettext_options = self.xgettext_options[:] + ["--no-wrap"] if options.get("no_location"): self.msgmerge_options = self.msgmerge_options[:] + ["--no-location"] self.msguniq_options = self.msguniq_options[:] + ["--no-location"] self.msgattrib_options = self.msgattrib_options[:] + ["--no-location"] self.xgettext_options = self.xgettext_options[:] + ["--no-location"] self.no_obsolete = options.get("no_obsolete") self.keep_pot = options.get("keep_pot") if locale is None and not exclude and not process_all: raise CommandError( "Type '%s help %s' for usage information." % (os.path.basename(sys.argv[0]), sys.argv[1]) ) self.invoked_for_django = False self.locale_paths = [] self.default_locale_path = None if os.path.isdir(os.path.join("conf", "locale")): self.locale_paths = [os.path.abspath(os.path.join("conf", "locale"))] self.default_locale_path = self.locale_paths[0] self.invoked_for_django = True else: self.locale_paths.extend(settings.LOCALE_PATHS) # Allow to run makemessages inside an app dir if os.path.isdir("locale"): self.locale_paths.append(os.path.abspath("locale")) if self.locale_paths: self.default_locale_path = self.locale_paths[0] if not os.path.exists(self.default_locale_path): os.makedirs(self.default_locale_path) # Build locale list locale_dirs = list( filter(os.path.isdir, glob.glob("%s/*" % self.default_locale_path)) ) all_locales = list(map(os.path.basename, locale_dirs)) # Account for excluded locales if process_all: locales = all_locales else: locales = locale or all_locales locales = set(locales) - set(exclude) if locales: check_programs("msguniq", "msgmerge", "msgattrib") check_programs("xgettext") try: potfiles = self.build_potfiles() # Build po files for each selected locale for locale in locales: if self.verbosity > 0: self.stdout.write("processing locale %s\n" % locale) for potfile in potfiles: self.write_po_file(potfile, locale) finally: if not self.keep_pot: self.remove_potfiles() def find_files(self, root): return [] def _emit_message(self, potfile, string): potfile.write( """ msgid "%s" msgstr "" """ % string.replace("\\", r"\\") .replace("\t", "\\t") .replace("\n", "\\n") .replace('"', '\\"') ) def process_files(self, file_list): with io.open( os.path.join(self.default_locale_path, "dmoj-user.pot"), "w", encoding="utf-8", ) as potfile: potfile.write( """ msgid "" msgstr "" "Content-Type: text/plain; charset=utf-8\\n" """) if self.verbosity > 1: self.stdout.write("processing navigation bar") for label in NavigationBar.objects.values_list("label", flat=True): if self.verbosity > 2: self.stdout.write('processing navigation item label "%s"\n' % label) self._emit_message(potfile, label) if self.verbosity > 1: self.stdout.write("processing problem types") for name in ProblemType.objects.values_list("full_name", flat=True): if self.verbosity > 2: self.stdout.write('processing problem type name "%s"\n' % name) self._emit_message(potfile, name)