Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

compilemessages.py 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import codecs
  2. import glob
  3. import os
  4. from django.core.management.base import BaseCommand, CommandError
  5. from django.core.management.utils import find_command, popen_wrapper
  6. def has_bom(fn):
  7. with open(fn, 'rb') as f:
  8. sample = f.read(4)
  9. return sample.startswith((codecs.BOM_UTF8, codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE))
  10. def is_writable(path):
  11. # Known side effect: updating file access/modified time to current time if
  12. # it is writable.
  13. try:
  14. with open(path, 'a'):
  15. os.utime(path, None)
  16. except (IOError, OSError):
  17. return False
  18. return True
  19. class Command(BaseCommand):
  20. help = 'Compiles .po files to .mo files for use with builtin gettext support.'
  21. requires_system_checks = False
  22. program = 'msgfmt'
  23. program_options = ['--check-format']
  24. def add_arguments(self, parser):
  25. parser.add_argument(
  26. '--locale', '-l', dest='locale', action='append', default=[],
  27. help='Locale(s) to process (e.g. de_AT). Default is to process all. '
  28. 'Can be used multiple times.',
  29. )
  30. parser.add_argument(
  31. '--exclude', '-x', dest='exclude', action='append', default=[],
  32. help='Locales to exclude. Default is none. Can be used multiple times.',
  33. )
  34. parser.add_argument(
  35. '--use-fuzzy', '-f', dest='fuzzy', action='store_true',
  36. help='Use fuzzy translations.',
  37. )
  38. def handle(self, **options):
  39. locale = options['locale']
  40. exclude = options['exclude']
  41. self.verbosity = options['verbosity']
  42. if options['fuzzy']:
  43. self.program_options = self.program_options + ['-f']
  44. if find_command(self.program) is None:
  45. raise CommandError("Can't find %s. Make sure you have GNU gettext "
  46. "tools 0.15 or newer installed." % self.program)
  47. basedirs = [os.path.join('conf', 'locale'), 'locale']
  48. if os.environ.get('DJANGO_SETTINGS_MODULE'):
  49. from django.conf import settings
  50. basedirs.extend(settings.LOCALE_PATHS)
  51. # Walk entire tree, looking for locale directories
  52. for dirpath, dirnames, filenames in os.walk('.', topdown=True):
  53. for dirname in dirnames:
  54. if dirname == 'locale':
  55. basedirs.append(os.path.join(dirpath, dirname))
  56. # Gather existing directories.
  57. basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs)))
  58. if not basedirs:
  59. raise CommandError("This script should be run from the Django Git "
  60. "checkout or your project or app tree, or with "
  61. "the settings module specified.")
  62. # Build locale list
  63. all_locales = []
  64. for basedir in basedirs:
  65. locale_dirs = filter(os.path.isdir, glob.glob('%s/*' % basedir))
  66. all_locales.extend(map(os.path.basename, locale_dirs))
  67. # Account for excluded locales
  68. locales = locale or all_locales
  69. locales = set(locales).difference(exclude)
  70. for basedir in basedirs:
  71. if locales:
  72. dirs = [os.path.join(basedir, l, 'LC_MESSAGES') for l in locales]
  73. else:
  74. dirs = [basedir]
  75. locations = []
  76. for ldir in dirs:
  77. for dirpath, dirnames, filenames in os.walk(ldir):
  78. locations.extend((dirpath, f) for f in filenames if f.endswith('.po'))
  79. if locations:
  80. self.compile_messages(locations)
  81. def compile_messages(self, locations):
  82. """
  83. Locations is a list of tuples: [(directory, file), ...]
  84. """
  85. for i, (dirpath, f) in enumerate(locations):
  86. if self.verbosity > 0:
  87. self.stdout.write('processing file %s in %s\n' % (f, dirpath))
  88. po_path = os.path.join(dirpath, f)
  89. if has_bom(po_path):
  90. raise CommandError("The %s file has a BOM (Byte Order Mark). "
  91. "Django only supports .po files encoded in "
  92. "UTF-8 and without any BOM." % po_path)
  93. base_path = os.path.splitext(po_path)[0]
  94. # Check writability on first location
  95. if i == 0 and not is_writable(base_path + '.mo'):
  96. self.stderr.write("The po files under %s are in a seemingly not writable location. "
  97. "mo files will not be updated/created." % dirpath)
  98. return
  99. args = [self.program] + self.program_options + [
  100. '-o', base_path + '.mo', base_path + '.po'
  101. ]
  102. output, errors, status = popen_wrapper(args)
  103. if status:
  104. if errors:
  105. msg = "Execution of %s failed: %s" % (self.program, errors)
  106. else:
  107. msg = "Execution of %s failed" % self.program
  108. raise CommandError(msg)