Ticket #17375: patch_17375_updated.diff
File patch_17375_updated.diff, 13.9 KB (added by , 13 years ago) |
---|
-
tests/regressiontests/i18n/commands/extraction.py
42 42 msgid = re.escape(msgid) 43 43 return self.assertTrue(re.search('^msgid %s' % msgid, s, re.MULTILINE), 'Could not find %(q)s%(n)s%(q)s in generated PO file' % {'n':needle, 'q':q}) 44 44 45 def assertMsgIdPlural(self, msgid, s, use_quotes=True): 46 q = '"' 47 if use_quotes: 48 msgid = '"%s"' % msgid 49 q = "'" 50 needle = 'msgid_plural %s' % msgid 51 msgid = re.escape(msgid) 52 return self.assertTrue(re.search('^msgid_plural %s' % msgid, s, re.MULTILINE), 'Could not find %(q)s%(n)s%(q)s in generated PO file' % {'n':needle, 'q':q}) 53 45 54 def assertNotMsgId(self, msgid, s, use_quotes=True): 46 55 if use_quotes: 47 56 msgid = '"%s"' % msgid … … 268 277 with open(self.PO_FILE, 'r') as fp: 269 278 po_contents = fp.read() 270 279 self.assertTrue('#: templates/test.html:55' in po_contents) 280 281 282 class MultipleFilesPluralExtractorTests(ExtractorTests): 283 284 def setUp(self): 285 self._cwd = os.getcwd() 286 self.test_dir = os.path.abspath(os.path.dirname(__file__)) 287 self.second_test_template = os.path.join(self.test_dir, 'templates', 'plural_test_template.html') 288 289 second_test_template = '''{% load i18n %}{% trans 'My string' %}''' 290 291 if not os.path.exists(self.second_test_template): 292 f = open(self.second_test_template, 'w+') 293 try: 294 f.write(second_test_template) 295 finally: 296 f.close() 297 298 def tearDown(self): 299 super(MultipleFilesPluralExtractorTests, self).tearDown() 300 os.chdir(self.test_dir) 301 try: 302 os.remove(self.second_test_template) 303 except OSError: 304 pass 305 os.chdir(self._cwd) 306 307 def test_multiple_files_plural_extraction(self): 308 os.chdir(self.test_dir) 309 management.call_command('makemessages', locale=LOCALE, verbosity=0, symlinks=True) 310 self.assertTrue(os.path.exists(self.PO_FILE)) 311 with open(self.PO_FILE, 'r') as fp: 312 po_contents = fp.read() 313 self.assertMsgId('My string', po_contents) 314 self.assertMsgIdPlural('My strings', po_contents) 315 No newline at end of file -
tests/regressiontests/i18n/commands/templates/test.html
77 77 {% trans "Shouldn't double escape this sequence %% either" context "ctx1" %} 78 78 {% trans "Looks like a str fmt spec %s but shouldn't be interpreted as such" %} 79 79 {% trans "Looks like a str fmt spec % o but shouldn't be interpreted as such" %} 80 {% blocktrans count counter=mylist|length %}My string{% plural %}My strings{% endblocktrans %} -
tests/regressiontests/i18n/tests.py
29 29 from .commands.extraction import (ExtractorTests, BasicExtractorTests, 30 30 JavascriptExtractorTests, IgnoredExtractorTests, SymlinkExtractorTests, 31 31 CopyPluralFormsExtractorTests, NoWrapExtractorTests, 32 NoLocationExtractorTests )32 NoLocationExtractorTests, MultipleFilesPluralExtractorTests) 33 33 if can_run_compilation_tests: 34 34 from .commands.compilation import (PoFileTests, PoFileContentsTests, 35 35 PercentRenderingTests) -
django/core/management/commands/makemessages.py
3 3 import os 4 4 import re 5 5 import sys 6 import tempfile 6 7 from itertools import dropwhile 7 8 from optparse import make_option 8 9 from subprocess import PIPE, Popen … … 127 128 break 128 129 return msgs 129 130 130 def write_pot_file(potfile, msgs, file, work_file, is_templatized):131 def write_pot_file(potfile, msgs, all_files): 131 132 """ 132 133 Write the :param potfile: POT file with the :param msgs: contents, 133 134 previously making sure its format is valid. 134 135 """ 135 if is_templatized: 136 old = '#: ' + work_file[2:] 137 new = '#: ' + file[2:] 138 msgs = msgs.replace(old, new) 136 for f_data in all_files: 137 if f_data['is_templatized']: 138 old = '#: ' + f_data['work'][2:] 139 new = '#: ' + f_data['orig'][2:] 140 msgs = msgs.replace(old, new) 139 141 if os.path.exists(potfile): 140 142 # Strip the header 141 143 msgs = '\n'.join(dropwhile(len, msgs.split('\n'))) … … 147 149 finally: 148 150 f.close() 149 151 150 def process_file (file, dirpath, potfile, domain, verbosity,151 extensions, wrap, location, stdout=sys.stdout):152 def process_files(potfile, domain, verbosity, extensions, wrap, location, 153 stdout, ignore_patterns, symlinks): 152 154 """ 153 Extract translatable literals from :param file:for :param domain:155 Extract translatable literals from current directory for :param domain: 154 156 creating or updating the :param potfile: POT file. 155 157 156 158 Uses the xgettext GNU gettext utility. 159 160 Procedure used is as follows: 161 1. Prepare template of xgettext command that will be executed 162 (depending on domain) - cmd 163 164 2. Parse all files and prepare list of dictionaries containing 165 information about each file that will be processed: 166 {'orig': '' # path to original file 167 'work': '' # path to either original file or templatized 168 # version if one will be created 169 'is_templatized': False # defines if file will be templatized 170 171 3. Create temporary file containing all filenames that are going to 172 be processed by xgettext 173 174 4. Execute xgettext command (cmd prepared in step 1) using path to 175 file created in step 4 176 177 5. If everything is ok: write POT file 178 If error occured while running xgettext: raise exception 179 180 6. For both success and error remove all templatized files that were 181 created 157 182 """ 158 159 183 from django.utils.translation import templatize 160 184 161 if verbosity > 1: 162 stdout.write('processing file %s in %s\n' % (file, dirpath)) 163 _, file_ext = os.path.splitext(file) 164 if domain == 'djangojs' and file_ext in extensions: 165 is_templatized = True 166 orig_file = os.path.join(dirpath, file) 167 src_data = open(orig_file).read() 168 src_data = prepare_js_for_gettext(src_data) 169 thefile = '%s.c' % file 170 work_file = os.path.join(dirpath, thefile) 171 f = open(work_file, "w") 172 try: 173 f.write(src_data) 174 finally: 175 f.close() 185 # stores information about all processed files 186 all_files = [] 187 188 # prepare command to run xgettext depending on domain type 189 if domain == 'djangojs': 176 190 cmd = ( 177 191 'xgettext -d %s -L C %s %s --keyword=gettext_noop ' 178 192 '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 ' 179 193 '--keyword=pgettext:1c,2 --keyword=npgettext:1c,2,3 ' 180 '--from-code UTF-8 --add-comments=Translators -o - "%s"' % 181 (domain, wrap, location, work_file)) 182 elif domain == 'django' and (file_ext == '.py' or file_ext in extensions): 183 thefile = file 184 orig_file = os.path.join(dirpath, file) 185 is_templatized = file_ext in extensions 186 if is_templatized: 187 src_data = open(orig_file, "rU").read() 188 thefile = '%s.py' % file 189 content = templatize(src_data, orig_file[2:]) 190 f = open(os.path.join(dirpath, thefile), "w") 191 try: 192 f.write(content) 193 finally: 194 f.close() 195 work_file = os.path.join(dirpath, thefile) 194 '--from-code UTF-8 --add-comments=Translators -o - -f %s' 195 ) 196 elif domain == 'django': 196 197 cmd = ( 197 198 'xgettext -d %s -L Python %s %s --keyword=gettext_noop ' 198 199 '--keyword=gettext_lazy --keyword=ngettext_lazy:1,2 ' … … 200 201 '--keyword=ungettext_lazy:1,2 --keyword=pgettext:1c,2 ' 201 202 '--keyword=npgettext:1c,2,3 --keyword=pgettext_lazy:1c,2 ' 202 203 '--keyword=npgettext_lazy:1c,2,3 --from-code UTF-8 ' 203 '--add-comments=Translators -o - "%s"' % 204 (domain, wrap, location, work_file)) 204 '--add-comments=Translators -o - -f %s' 205 ) 206 207 # check all files and prepare list of dictionaries containing information 208 # about each file that is going to be processed by xgettext 209 for dirpath, file in find_files(".", ignore_patterns, verbosity, 210 stdout, symlinks=symlinks): 211 file_dict = process_file(file, dirpath, domain, verbosity, 212 extensions, stdout) 213 if file_dict: 214 all_files.append(file_dict) 215 216 if all_files: 217 # Prepare command that runs xgettext. 218 # Part of this command is a path to config file that 219 # contains paths of all files to be processed 220 input_files = '\n'.join([f_data['work'] for f_data in all_files]) 221 222 # create temporary config file for xgettext 223 f_handle, input_files_path = tempfile.mkstemp() 224 f = open(input_files_path, 'w') 225 try: 226 f.write(input_files) 227 finally: 228 f.close() 229 230 # run xgettext against temporary config file 231 cmd = cmd % (domain, wrap, location, input_files_path) 232 msgs, errors = _popen(cmd) 233 234 # remove temporary config file 235 os.unlink(input_files_path) 236 237 if errors: 238 # if error(s) occured we have to remove all templatized files 239 # We have to check if file exists because when symlinks are used it might 240 # happen that file was already removed 241 [os.unlink(f_data['work']) for f_data in all_files 242 if f_data['is_templatized'] and os.path.exists(f_data['work'])] 243 244 input_files = ', '.join([f_data['work'] for f_data in all_files]) 245 raise CommandError( 246 "errors happened while running xgettext on %s\n%s" % 247 (input_files, errors)) 248 249 if msgs: 250 write_pot_file(potfile, msgs, all_files) 251 # check if file exists because when symlinks are used it might 252 # happen that file was already removed 253 [os.unlink(f_data['work']) for f_data in all_files 254 if f_data['is_templatized'] and os.path.exists(f_data['work'])] 255 256 def process_file(file, dirpath, domain, verbosity, 257 extensions, stdout=sys.stdout): 258 """ 259 Extract translatable literals from :param file: for :param domain: 260 and return dictionary containing informations about original file path, 261 and path to templatized file if one was created. 262 """ 263 264 from django.utils.translation import templatize 265 266 if verbosity > 1: 267 stdout.write('processing file %s in %s\n' % (file, dirpath)) 268 _, file_ext = os.path.splitext(file) 269 270 is_templatized = file_ext in extensions 271 272 # path to the processed file 273 orig_file_path = os.path.join(dirpath, file) 274 275 # prepare information about processed file; 276 # 'orig' - path to original file 277 # 'work' - path to either original file or templatized version if one will be created 278 # 'is_templatized' - defines if file will be templatized 279 file_dict = {'orig': orig_file_path, 280 'work': orig_file_path, 281 'is_templatized': is_templatized} 282 283 # if file is going to be templatized then we have to create its special 284 # version prepared for gettext and save it with new filename 285 if domain == 'djangojs' and is_templatized: 286 src_data = open(orig_file_path).read() 287 content = prepare_js_for_gettext(src_data) 288 thefile = '%s.c' % file 289 elif domain == 'django' and (file_ext == '.py' or is_templatized): 290 if is_templatized: 291 src_data = open(orig_file_path, "rU").read() 292 content = templatize(src_data, orig_file_path[2:]) 293 thefile = '%s.py' % file 205 294 else: 206 295 return 207 msgs, errors = _popen(cmd) 208 if errors: 209 if is_templatized: 210 os.unlink(work_file) 211 if os.path.exists(potfile): 212 os.unlink(potfile) 213 raise CommandError( 214 "errors happened while running xgettext on %s\n%s" % 215 (file, errors)) 216 if msgs: 217 write_pot_file(potfile, msgs, orig_file, work_file, is_templatized) 296 218 297 if is_templatized: 219 os.unlink(work_file) 298 # for templatized files create work file 299 work_file = os.path.join(dirpath, thefile) 300 file_dict['work'] = work_file 220 301 302 f = open(work_file, "w") 303 try: 304 f.write(content) 305 finally: 306 f.close() 307 return file_dict 308 221 309 def write_po_file(pofile, potfile, domain, locale, verbosity, stdout, 222 310 copy_pforms, wrap, location, no_obsolete): 223 311 """ … … 335 423 if os.path.exists(potfile): 336 424 os.unlink(potfile) 337 425 338 for dirpath, file in find_files(".", ignore_patterns, verbosity, 339 stdout, symlinks=symlinks): 340 process_file(file, dirpath, potfile, domain, verbosity, extensions, 341 wrap, location, stdout) 426 process_files(potfile, domain, verbosity, extensions, 427 wrap, location, stdout, ignore_patterns, symlinks) 342 428 343 429 if os.path.exists(potfile): 344 430 write_po_file(pofile, potfile, domain, locale, verbosity, stdout,