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

Unified Diff: localeTools.py

Issue 29556601: Issue 5777 - Update crowdin interface (Closed)
Patch Set: Purged obsolete distinguishing between crowdin_{get|post} Created Sept. 26, 2017, 2:46 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 = {}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld