| Index: localeTools.py |
| diff --git a/localeTools.py b/localeTools.py |
| index 140f22c1f7bb8298ce12bf7c1d4547a47de346a4..d9f4c40132fce86a5df98b0a7d85bb39005b54f7 100644 |
| --- a/localeTools.py |
| +++ b/localeTools.py |
| @@ -7,6 +7,7 @@ import os |
| import sys |
| import codecs |
| import json |
| +import urlparse |
| import urllib |
| import urllib2 |
| from StringIO import StringIO |
| @@ -92,6 +93,46 @@ chromeLocales = [ |
| 'zh-TW', |
| ] |
| +CROWDIN_AP_URL = 'https://api.crowdin.com/api/project/{}/{}' |
| + |
| + |
| +def crowdin_url(project_name, action, key, get={}): |
| + """Create a valid url for a crowdin endpoint.""" |
| + url = CROWDIN_AP_URL.format(project_name, action) |
| + get['key'] = key |
| + |
| + scheme, netloc, path, params, query, fragment = urlparse.urlparse(url) |
| + |
| + query = dict(urlparse.parse_qsl(query)) |
|
Sebastian Noack
2017/09/27 04:04:53
Is there any way that there will be a query part h
tlucas
2017/09/27 10:51:31
Discussion with Vasily:
On 2017/09/26 13:11:36, V
Sebastian Noack
2017/09/28 20:25:21
So it seems Vasily agrees with me. Anyway, if you
|
| + query.update(get) |
| + |
| + return urlparse.urlunparse(( |
| + scheme, netloc, path, params, urllib.urlencode(query), fragment |
| + )) |
| + |
| + |
| +def crowdin_request(project_name, action, key, get={}, post_data=None, |
|
tlucas
2017/09/26 14:49:05
crowdin_request can perfectly handle both get and
|
| + headers={}, raises=False): |
| + """Perform a call to crowdin and raise an Exception on failure.""" |
| + |
| + request = urllib2.Request( |
| + crowdin_url(project_name, action, key, get), |
| + post_data, |
| + headers, |
| + ) |
| + |
| + result = urllib2.urlopen(request).read() |
| + |
| + if raises and result.find('<success') < 0: |
|
Sebastian Noack
2017/09/27 04:04:52
Note that `result.find('<success') < 0` is equival
Sebastian Noack
2017/09/27 04:04:53
Why is a flag necessary to opt-in for error checki
tlucas
2017/09/27 10:51:31
After further investigation, it seems like relying
|
| + raise Exception( |
| + 'Server indicated that the operation was not successful\n' + result |
| + ) |
| + |
| + if 'json' in get: |
| + result = json.loads(result) |
| + |
| + return result |
| + |
| class OrderedDict(dict): |
| def __init__(self): |
| @@ -297,23 +338,24 @@ def setupTranslations(localeConfig, projectName, key): |
| locales.add(mapLocale('BCP-47', match2.group(1))) |
| allowed = set() |
| - allowedLocales = json.load(urllib2.urlopen( |
| - 'https://crowdin.com/languages/languages_list?callback=' |
| - )) |
| + allowedLocales = crowdin_request(projectName, 'supported-languages', key, |
| + {'json': 1}) |
|
Sebastian Noack
2017/09/27 04:04:53
I wonder what would happen if we always set json=1
tlucas
2017/09/27 10:51:31
There would be only one case where we explicitly e
|
| + |
| for locale in allowedLocales: |
| - allowed.add(locale['code']) |
| + allowed.add(locale['crowdin_code']) |
| if not allowed.issuperset(locales): |
| print "Warning, following locales aren't allowed by server: " + ', '.join(locales - allowed) |
| locales = list(locales & allowed) |
| locales.sort() |
| params = urllib.urlencode([('languages[]', locale) for locale in locales]) |
| - result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/edit-project?key=%s' % (projectName, key), params).read() |
| - if result.find('<success') < 0: |
| - raise Exception('Server indicated that the operation was not successful\n' + result) |
| + |
| + crowdin_request(projectName, 'edit-project', key, post_data=params, |
| + raises=True) |
| -def postFiles(files, url): |
| +def crowdin_body_headers(files): |
| + """Create a post body and according headers, which Crowdin can handle.""" |
| boundary = '----------ThIs_Is_tHe_bouNdaRY_$' |
| body = '' |
| for file, data in files: |
| @@ -325,16 +367,17 @@ def postFiles(files, url): |
| body += '--%s--\r\n' % boundary |
| body = body.encode('utf-8') |
|
Sebastian Noack
2017/09/27 04:04:52
This seems unrelated, but I noticed that the encod
tlucas
2017/09/27 10:51:30
Done.
|
| - request = urllib2.Request(url, StringIO(body)) |
| - request.add_header('Content-Type', 'multipart/form-data; boundary=%s' % boundary) |
| - request.add_header('Content-Length', len(body)) |
| - result = urllib2.urlopen(request).read() |
| - if result.find('<success') < 0: |
| - raise Exception('Server indicated that the operation was not successful\n' + result) |
| + return ( |
| + StringIO(body), |
| + { |
| + 'Content-Type': 'multipart/form-data; boundary=%s' % boundary, |
| + 'Content-Length': len(body) |
| + } |
| + ) |
| def updateTranslationMaster(localeConfig, metadata, dir, projectName, key): |
| - result = json.load(urllib2.urlopen('http://api.crowdin.net/api/project/%s/info?key=%s&json=1' % (projectName, key))) |
| + result = crowdin_request(projectName, 'info', key, {'json': 1}) |
| existing = set(map(lambda f: f['name'], result['files'])) |
| add = [] |
| @@ -362,14 +405,18 @@ def updateTranslationMaster(localeConfig, metadata, dir, projectName, key): |
| add.append((newName, data)) |
| if len(add): |
| - titles = urllib.urlencode([('titles[%s]' % name, re.sub(r'\.json', '', name)) for name, data in add]) |
| - postFiles(add, 'http://api.crowdin.net/api/project/%s/add-file?key=%s&type=chrome&%s' % (projectName, key, titles)) |
| + data = {'titles[{}]'.format(name): re.sub(r'\.json', '', name) |
|
Sebastian Noack
2017/09/27 04:04:53
`re.sub(r'\.json', '', name)` is equivalent to `na
tlucas
2017/09/27 10:51:31
I honestly don't know what Wladimir's intention wa
Sebastian Noack
2017/09/28 20:25:21
Yes, if removing each occurrence of the sub-string
|
| + for name, data in add} |
| + data['type'] = 'chrome' |
| + data, headers = crowdin_body_headers(add) |
| + crowdin_request(projectName, 'add-file', key, post_data=data, |
| + headers=headers, raises=True) |
| if len(update): |
| - postFiles(update, 'http://api.crowdin.net/api/project/%s/update-file?key=%s' % (projectName, key)) |
| + data, headers = crowdin_body_headers(update) |
| + crowdin_request(projectName, 'update-file', key, post_data=data, |
| + headers=headers, raises=True) |
| for file in existing: |
| - result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/delete-file?key=%s&file=%s' % (projectName, key, file)).read() |
| - if result.find('<success') < 0: |
| - raise Exception('Server indicated that the operation was not successful\n' + result) |
| + crowdin_request(projectName, 'delete-file', key, {'file': file}) |
| def uploadTranslations(localeConfig, metadata, dir, locale, projectName, key): |
| @@ -392,17 +439,18 @@ def uploadTranslations(localeConfig, metadata, dir, locale, projectName, key): |
| if data: |
| files.append((newName, data)) |
| if len(files): |
| - postFiles(files, 'http://api.crowdin.net/api/project/%s/upload-translation?key=%s&language=%s' % ( |
| - projectName, key, mapLocale(localeConfig['name_format'], locale)) |
| - ) |
| + language = mapLocale(localeConfig['name_format'], locale) |
| + data, headers = crowdin_body_headers(files) |
| + crowdin_request(projectName, 'upload-translation', key, |
| + {'language': language}, post_data=data, |
| + headers=headers, raises=True) |
| def getTranslations(localeConfig, projectName, key): |
| - result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/export?key=%s' % (projectName, key)).read() |
| - if result.find('<success') < 0: |
| - raise Exception('Server indicated that the operation was not successful\n' + result) |
| + # let crowdin build the project |
| + crowdin_request(projectName, 'export', key, raises=True) |
| - result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/download/all.zip?key=%s' % (projectName, key)).read() |
| + result = crowdin_request(projectName, 'download/all.zip', key) |
|
tlucas
2017/09/27 10:51:31
This will be the only call expecting the response
|
| zip = ZipFile(StringIO(result)) |
| dirs = {} |