| Left: | ||
| Right: |
| LEFT | RIGHT |
|---|---|
| 1 # coding: utf-8 | 1 # coding: utf-8 |
| 2 | 2 |
| 3 # This Source Code is subject to the terms of the Mozilla Public License | 3 # This Source Code is subject to the terms of the Mozilla Public License |
| 4 # version 2.0 (the "License"). You can obtain a copy of the License at | 4 # version 2.0 (the "License"). You can obtain a copy of the License at |
| 5 # http://mozilla.org/MPL/2.0/. | 5 # http://mozilla.org/MPL/2.0/. |
| 6 | 6 |
| 7 import re, os, sys, codecs, json, urllib, urllib2 | 7 import re, os, sys, codecs, json, urllib, urllib2 |
| 8 from StringIO import StringIO | 8 from StringIO import StringIO |
| 9 from ConfigParser import SafeConfigParser | 9 from ConfigParser import SafeConfigParser |
| 10 from zipfile import ZipFile | 10 from zipfile import ZipFile |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 data = json.load(fileHandle) | 235 data = json.load(fileHandle) |
| 236 fileHandle.close() | 236 fileHandle.close() |
| 237 | 237 |
| 238 # Remove synced keys, these don't need to be translated | 238 # Remove synced keys, these don't need to be translated |
| 239 if metadata.has_section('locale_sync'): | 239 if metadata.has_section('locale_sync'): |
| 240 for file, stringIDs in metadata.items('locale_sync'): | 240 for file, stringIDs in metadata.items('locale_sync'): |
| 241 for stringID in re.split(r'\s+', stringIDs): | 241 for stringID in re.split(r'\s+', stringIDs): |
| 242 if file == 'remove': | 242 if file == 'remove': |
| 243 key = stringID | 243 key = stringID |
| 244 else: | 244 else: |
| 245 key = re.sub(r'\..*', '', file) + '_' + re.sub(r'\W', '_', stringID) | 245 key = re.sub(r'\..*', '', file) + '_' + re.sub(r'\W', '_', stringID) |
|
Felix Dahlke
2013/01/10 16:36:20
We have pretty much the same line in localeSyncChr
Wladimir Palant
2013/01/16 14:20:15
Yes, the idea is to make locale syncing part of th
| |
| 246 if key in data: | 246 if key in data: |
| 247 del data[key] | 247 del data[key] |
| 248 | 248 |
| 249 for key, value in data.iteritems(): | 249 for key, value in data.iteritems(): |
| 250 if isMaster: | 250 if isMaster: |
| 251 # Make sure the key name is listed in the description | 251 # Make sure the key name is listed in the description |
| 252 if "description" in value: | 252 if "description" in value: |
| 253 value["description"] = "%s: %s" % (key, value["description"]) | 253 value["description"] = "%s: %s" % (key, value["description"]) |
| 254 else: | 254 else: |
| 255 value["description"] = key | 255 value["description"] = key |
| 256 else: | 256 else: |
| 257 # Delete description from translations | 257 # Delete description from translations |
| 258 if "description" in value: | 258 if "description" in value: |
| 259 del value["description"] | 259 del value["description"] |
| 260 | 260 |
| 261 return json.dumps(data, ensure_ascii=False, sort_keys=True, indent=2) | 261 return json.dumps(data, ensure_ascii=False, sort_keys=True, indent=2) |
| 262 | 262 |
| 263 def postprocessChromeLocale(path, data): | |
| 264 parsed = json.loads(data) | |
| 265 | |
| 266 # Delete description from translations | |
| 267 for key, value in parsed.iteritems(): | |
| 268 if "description" in value: | |
| 269 del value["description"] | |
| 270 | |
| 271 file = codecs.open(path, 'wb', encoding='utf-8') | |
| 272 json.dump(parsed, file, ensure_ascii=False, sort_keys=True, indent=2, separato rs=(',', ': ')) | |
| 273 file.close() | |
| 274 | |
| 263 def setupTranslations(type, locales, projectName, key): | 275 def setupTranslations(type, locales, projectName, key): |
| 264 # Copy locales list, we don't want to change the parameter | 276 # Copy locales list, we don't want to change the parameter |
| 265 locales = set(locales) | 277 locales = set(locales) |
| 266 | 278 |
| 267 # Fill up with locales that we don't have but the browser supports | 279 # Fill up with locales that we don't have but the browser supports |
| 268 if type == 'chrome': | 280 if type == 'chrome': |
| 269 for locale in chromeLocales: | 281 for locale in chromeLocales: |
| 270 locales.add(locale) | 282 locales.add(locale) |
| 271 else: | 283 else: |
| 272 firefoxLocales = urllib2.urlopen('http://www.mozilla.org/en-US/firefox/all.h tml').read() | 284 firefoxLocales = urllib2.urlopen('http://www.mozilla.org/en-US/firefox/all.h tml').read() |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 290 print 'Warning, following locales aren\'t allowed by server: ' + ', '.join(l ocales - allowed) | 302 print 'Warning, following locales aren\'t allowed by server: ' + ', '.join(l ocales - allowed) |
| 291 | 303 |
| 292 locales = list(locales & allowed) | 304 locales = list(locales & allowed) |
| 293 locales.sort() | 305 locales.sort() |
| 294 params = urllib.urlencode([('languages[]', locale) for locale in locales]) | 306 params = urllib.urlencode([('languages[]', locale) for locale in locales]) |
| 295 result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/edit-project?k ey=%s&%s' % (projectName, key, params)).read() | 307 result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/edit-project?k ey=%s&%s' % (projectName, key, params)).read() |
| 296 if result.find('<success') < 0: | 308 if result.find('<success') < 0: |
| 297 raise Exception('Server indicated that the operation was not successful\n' + result) | 309 raise Exception('Server indicated that the operation was not successful\n' + result) |
| 298 | 310 |
| 299 def postFiles(files, url): | 311 def postFiles(files, url): |
| 300 boundary = '----------ThIs_Is_tHe_bouNdaRY_$' | 312 boundary = '----------ThIs_Is_tHe_bouNdaRY_$' |
|
Felix Dahlke
2013/01/10 16:36:20
Would it make sense to generate this randomly?
Wladimir Palant
2013/01/16 14:20:15
I'm not sure where this boundary string originates
| |
| 301 body = '' | 313 body = '' |
| 302 for file, data in files: | 314 for file, data in files: |
| 303 body += '--%s\r\n' % boundary | 315 body += '--%s\r\n' % boundary |
| 304 body += 'Content-Disposition: form-data; name="files[%s]"; filename="%s"\r\n ' % (file, file) | 316 body += 'Content-Disposition: form-data; name="files[%s]"; filename="%s"\r\n ' % (file, file) |
| 305 body += 'Content-Type: application/octet-stream\r\n' | 317 body += 'Content-Type: application/octet-stream\r\n' |
| 306 body += 'Content-Transfer-Encoding: binary\r\n' | 318 body += 'Content-Transfer-Encoding: binary\r\n' |
| 307 body += '\r\n' + data + '\r\n' | 319 body += '\r\n' + data + '\r\n' |
| 308 body += '--%s--\r\n' % boundary | 320 body += '--%s--\r\n' % boundary |
| 309 | 321 |
| 310 body = body.encode('utf-8') | 322 body = body.encode('utf-8') |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 newName = file | 370 newName = file |
| 359 else: | 371 else: |
| 360 data = toJSON(path) | 372 data = toJSON(path) |
| 361 newName = file + '.json' | 373 newName = file + '.json' |
| 362 | 374 |
| 363 if data: | 375 if data: |
| 364 files.append((newName, data)) | 376 files.append((newName, data)) |
| 365 if len(files): | 377 if len(files): |
| 366 postFiles(files, 'http://api.crowdin.net/api/project/%s/upload-translation?k ey=%s&language=%s' % (projectName, key, mapLocale(type, locale))) | 378 postFiles(files, 'http://api.crowdin.net/api/project/%s/upload-translation?k ey=%s&language=%s' % (projectName, key, mapLocale(type, locale))) |
| 367 | 379 |
| 368 def getTranslations(localesDir, defaultLocale, projectName, key): | 380 def getTranslations(type, localesDir, defaultLocale, projectName, key): |
| 369 result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/export?key=%s' % (projectName, key)).read() | 381 result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/export?key=%s' % (projectName, key)).read() |
| 370 if result.find('<success') < 0: | 382 if result.find('<success') < 0: |
| 371 raise Exception('Server indicated that the operation was not successful\n' + result) | 383 raise Exception('Server indicated that the operation was not successful\n' + result) |
| 372 | 384 |
| 373 result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/download/all.z ip?key=%s' % (projectName, key)).read() | 385 result = urllib2.urlopen('http://api.crowdin.net/api/project/%s/download/all.z ip?key=%s' % (projectName, key)).read() |
| 374 zip = ZipFile(StringIO(result)) | 386 zip = ZipFile(StringIO(result)) |
| 375 dirs = {} | 387 dirs = {} |
| 376 for info in zip.infolist(): | 388 for info in zip.infolist(): |
| 377 if not info.filename.endswith('.dtd.json') and not info.filename.endswith('. properties.json'): | 389 if not info.filename.endswith('.json'): |
| 378 continue | 390 continue |
| 379 | 391 |
| 380 dir, file = os.path.split(info.filename) | 392 dir, file = os.path.split(info.filename) |
| 381 origFile = re.sub(r'\.json$', '', file) | |
| 382 if not re.match(r'^[\w\-]+$', dir) or dir == defaultLocale: | 393 if not re.match(r'^[\w\-]+$', dir) or dir == defaultLocale: |
| 383 continue | 394 continue |
| 384 | 395 if type == 'chrome': |
| 385 for key, value in langMappingGecko.iteritems(): | 396 origFile = file |
| 397 else: | |
| 398 origFile = re.sub(r'\.json$', '', file) | |
| 399 if not origFile.endswith('.dtd') and not origFile.endswith('.properties'): | |
| 400 continue | |
| 401 | |
| 402 mapping = langMappingChrome if type == 'chrome' else langMappingGecko | |
| 403 for key, value in mapping.iteritems(): | |
| 386 if value == dir: | 404 if value == dir: |
| 387 dir = key | 405 dir = key |
| 406 if type == 'chrome': | |
| 407 dir = dir.replace('-', '_') | |
| 408 | |
| 409 data = zip.open(info.filename).read() | |
| 410 if data == '[]': | |
| 411 continue | |
| 388 | 412 |
| 389 if not dir in dirs: | 413 if not dir in dirs: |
| 390 dirs[dir] = set() | 414 dirs[dir] = set() |
| 391 dirs[dir].add(origFile) | 415 dirs[dir].add(origFile) |
| 392 | 416 |
| 393 data = zip.open(info.filename).read() | 417 path = os.path.join(localesDir, dir, origFile) |
| 394 fromJSON(os.path.join(localesDir, dir, origFile), data) | 418 if not os.path.exists(os.path.dirname(path)): |
| 419 os.makedirs(os.path.dirname(path)) | |
| 420 if type == 'chrome': | |
| 421 postprocessChromeLocale(path, data) | |
| 422 else: | |
| 423 fromJSON(path, data) | |
| 395 | 424 |
| 396 # Remove any extra files | 425 # Remove any extra files |
| 397 for dir, files in dirs.iteritems(): | 426 for dir, files in dirs.iteritems(): |
| 398 baseDir = os.path.join(localesDir, dir) | 427 baseDir = os.path.join(localesDir, dir) |
| 399 if not os.path.exists(baseDir): | 428 if not os.path.exists(baseDir): |
| 400 continue | 429 continue |
| 401 for file in os.listdir(baseDir): | 430 for file in os.listdir(baseDir): |
| 402 path = os.path.join(baseDir, file) | 431 path = os.path.join(baseDir, file) |
| 403 if os.path.isfile(path) and (file.endswith('.properties') or file.endswith ('.dtd')) and not file in files: | 432 if os.path.isfile(path) and (file.endswith('.json') or file.endswith('.pro perties') or file.endswith('.dtd')) and not file in files: |
| 404 os.remove(path) | 433 os.remove(path) |
| LEFT | RIGHT |