Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: localeTools.py

Issue 29556601: Issue 5777 - Update crowdin interface (Closed)
Left Patch Set: Belatedly addressed Sebastian's comments Created Sept. 28, 2017, 9:29 p.m.
Right Patch Set: Mimetype, PEP-8 Created Sept. 29, 2017, 9:07 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 # This Source Code Form is subject to the terms of the Mozilla Public 1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4 4
5 import re 5 import re
6 import os 6 import os
7 import sys 7 import sys
8 import codecs 8 import codecs
9 import json 9 import json
10 import urlparse 10 import urlparse
11 import urllib 11 import urllib
12 import urllib2 12 import urllib2
13 import mimetypes
13 from StringIO import StringIO 14 from StringIO import StringIO
14 from ConfigParser import SafeConfigParser 15 from ConfigParser import SafeConfigParser
15 from zipfile import ZipFile 16 from zipfile import ZipFile
16 from xml.parsers.expat import ParserCreate, XML_PARAM_ENTITY_PARSING_ALWAYS 17 from xml.parsers.expat import ParserCreate, XML_PARAM_ENTITY_PARSING_ALWAYS
17 18
18 langMappingGecko = { 19 langMappingGecko = {
19 'bn-BD': 'bn', 20 'bn-BD': 'bn',
20 'br': 'br-FR', 21 'br': 'br-FR',
21 'dsb': 'dsb-DE', 22 'dsb': 'dsb-DE',
22 'fj-FJ': 'fj', 23 'fj-FJ': 'fj',
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 'tr', 90 'tr',
90 'uk', 91 'uk',
91 'vi', 92 'vi',
92 'zh-CN', 93 'zh-CN',
93 'zh-TW', 94 'zh-TW',
94 ] 95 ]
95 96
96 CROWDIN_AP_URL = 'https://api.crowdin.com/api/project' 97 CROWDIN_AP_URL = 'https://api.crowdin.com/api/project'
97 98
98 99
99 def crowdin_url(project_name, action, key, get={}):
100 """Create a valid url for a crowdin endpoint."""
101 return '{}/{}/{}?{}'.format(CROWDIN_AP_URL,
tlucas 2017/09/28 21:33:58 as discussed: simpler building of the desired url
Sebastian Noack 2017/09/28 22:18:37 Is this even worth a separate function now? I woul
tlucas 2017/09/29 09:09:37 I agree, no extra function necessary - Done.
102 urllib.quote(project_name),
103 urllib.quote(action),
104 urllib.urlencode(dict(get, key=key, json=1)))
105
106
107 def crowdin_request(project_name, action, key, get={}, post_data=None, 100 def crowdin_request(project_name, action, key, get={}, post_data=None,
108 headers={}, raw=False): 101 headers={}, raw=False):
109 """Perform a call to crowdin and raise an Exception on failure.""" 102 """Perform a call to crowdin and raise an Exception on failure."""
110 request = urllib2.Request( 103 request = urllib2.Request(
111 crowdin_url(project_name, action, key, get), 104 '{}/{}/{}?{}'.format(CROWDIN_AP_URL,
105 urllib.quote(project_name),
106 urllib.quote(action),
107 urllib.urlencode(dict(get, key=key, json=1))),
112 post_data, 108 post_data,
113 headers, 109 headers,
114 ) 110 )
115 111
116 try: 112 try:
117 result = urllib2.urlopen(request).read() 113 result = urllib2.urlopen(request).read()
118 except urllib2.HTTPError as e: 114 except urllib2.HTTPError as e:
119 raise Exception('Server returned HTTP Error {}:\n{}'.format(e.code, 115 raise Exception('Server returned HTTP Error {}:\n{}'.format(e.code,
120 e.read())) 116 e.read()))
121 117
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 params = urllib.urlencode([('languages[]', locale) for locale in locales]) 337 params = urllib.urlencode([('languages[]', locale) for locale in locales])
342 338
343 crowdin_request(projectName, 'edit-project', key, post_data=params) 339 crowdin_request(projectName, 'edit-project', key, post_data=params)
344 340
345 341
346 def crowdin_prepare_upload(files): 342 def crowdin_prepare_upload(files):
347 """Create a post body and matching headers, which Crowdin can handle.""" 343 """Create a post body and matching headers, which Crowdin can handle."""
348 boundary = '----------ThIs_Is_tHe_bouNdaRY_$' 344 boundary = '----------ThIs_Is_tHe_bouNdaRY_$'
349 body = '' 345 body = ''
350 for name, data in files: 346 for name, data in files:
351 body += ('--{boundary}\r\n' 347 mimetype = mimetypes.guess_type(name)[0]
352 'Content-Disposition: form-data; name="files[{name}]"; ' 348 body += (
353 'filename="{name}"\r\n' 349 '--{boundary}\r\n'
Sebastian Noack 2017/09/28 22:18:37 Nit: You can avoid wrapping before the end of line
tlucas 2017/09/29 09:09:37 Done.
354 'Content-Type: application/octet-stream; charset=utf-8\r\n' 350 'Content-Disposition: form-data; name="files[{name}]"; '
tlucas 2017/09/28 21:33:58 as discussed: charset in each file's individual Co
Sebastian Noack 2017/09/28 22:18:37 This should be "application/json", I guess?
Sebastian Noack 2017/09/28 22:51:55 Or even better, you could dynamically detect the t
tlucas 2017/09/29 09:09:37 Good point - Done.
355 'Content-Transfer-Encoding: binary\r\n' 351 'filename="{name}"\r\n'
356 '\r\n{data}\r\n' 352 'Content-Type: {mimetype}; charset=utf-8\r\n'
357 '--{boundary}--\r\n').format(boundary=boundary, name=name, 353 'Content-Transfer-Encoding: binary\r\n'
358 data=data) 354 '\r\n{data}\r\n'
355 '--{boundary}--\r\n'
356 ).format(boundary=boundary, name=name, data=data, mimetype=mimetype)
359 357
360 body = body.encode('utf-8') 358 body = body.encode('utf-8')
361 return ( 359 return (
362 StringIO(body), 360 StringIO(body),
363 { 361 {
364 'Content-Type': ('multipart/form-data; boundary=' + boundary), 362 'Content-Type': ('multipart/form-data; boundary=' + boundary),
365 'Content-Length': len(body) 363 'Content-Length': len(body)
366 }, 364 },
367 ) 365 )
368 366
(...skipping 20 matching lines...) Expand all
389 newName = file + '.json' 387 newName = file + '.json'
390 388
391 if data: 389 if data:
392 if newName in existing: 390 if newName in existing:
393 update.append((newName, data)) 391 update.append((newName, data))
394 existing.remove(newName) 392 existing.remove(newName)
395 else: 393 else:
396 add.append((newName, data)) 394 add.append((newName, data))
397 395
398 if len(add): 396 if len(add):
399 query = {'titles[{}]'.format(name): os.path.splitext(name)[0] 397 query = {'titles[{}]'.format(name): os.path.splitext(name)[0]
tlucas 2017/09/28 21:33:58 os.path.splitext as discussed
400 for name, _ in add} 398 for name, _ in add}
401 query['type'] = 'chrome' 399 query['type'] = 'chrome'
402 data, headers = crowdin_prepare_upload(add) 400 data, headers = crowdin_prepare_upload(add)
403 crowdin_request(projectName, 'add-file', key, query, post_data=data, 401 crowdin_request(projectName, 'add-file', key, query, post_data=data,
tlucas 2017/09/28 21:33:58 Hasn't benn noticed before: the query was overwrit
404 headers=headers) 402 headers=headers)
405 if len(update): 403 if len(update):
406 data, headers = crowdin_prepare_upload(update) 404 data, headers = crowdin_prepare_upload(update)
407 crowdin_request(projectName, 'update-file', key, post_data=data, 405 crowdin_request(projectName, 'update-file', key, post_data=data,
408 headers=headers) 406 headers=headers)
409 for file in existing: 407 for file in existing:
410 crowdin_request(projectName, 'delete-file', key, {'file': file}) 408 crowdin_request(projectName, 'delete-file', key, {'file': file})
411 409
412 410
413 def uploadTranslations(localeConfig, metadata, dir, locale, projectName, key): 411 def uploadTranslations(localeConfig, metadata, dir, locale, projectName, key):
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 504
507 # Remove any extra files 505 # Remove any extra files
508 for dir, files in dirs.iteritems(): 506 for dir, files in dirs.iteritems():
509 baseDir = os.path.join(localeConfig['base_path'], dir) 507 baseDir = os.path.join(localeConfig['base_path'], dir)
510 if not os.path.exists(baseDir): 508 if not os.path.exists(baseDir):
511 continue 509 continue
512 for file in os.listdir(baseDir): 510 for file in os.listdir(baseDir):
513 path = os.path.join(baseDir, file) 511 path = os.path.join(baseDir, file)
514 if os.path.isfile(path) and (file.endswith('.json') or file.endswith ('.properties') or file.endswith('.dtd')) and not file in files: 512 if os.path.isfile(path) and (file.endswith('.json') or file.endswith ('.properties') or file.endswith('.dtd')) and not file in files:
515 os.remove(path) 513 os.remove(path)
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld