Skip to content

Commit

Permalink
Add command to rebuild messages and pull translations from transifex
Browse files Browse the repository at this point in the history
  • Loading branch information
rowanseymour committed Jul 7, 2021
1 parent 097b846 commit a783322
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 52 deletions.
6 changes: 1 addition & 5 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,7 @@ omit =
temba/flows/management/commands/run_audit.py
temba/msgs/management/commands/msg_console.py
temba/orgs/management/commands/*
temba/utils/management/commands/mailroom_db.py
temba/utils/management/commands/migrate_flows.py
temba/utils/management/commands/test_db.py
temba/utils/management/commands/perf_test.py
temba/utils/management/commands/verify_sentry.py
temba/utils/management/commands/*
[html]
directory = coverage_html_report
6 changes: 1 addition & 5 deletions .coveragerc_todo
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,7 @@ omit =
temba/flows/management/commands/run_audit.py
temba/msgs/management/commands/msg_console.py
temba/orgs/management/commands/*
temba/utils/management/commands/mailroom_db.py
temba/utils/management/commands/migrate_flows.py
temba/utils/management/commands/test_db.py
temba/utils/management/commands/perf_test.py
temba/utils/management/commands/verify_sentry.py
temba/utils/management/commands/*

[html]
directory = coverage_html_report
42 changes: 0 additions & 42 deletions code_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
import subprocess

import colorama
import polib

parser = argparse.ArgumentParser(description="Code checks")
parser.add_argument("--skip-compilemessages", action="store_true")
parser.add_argument("--skip-flake", action="store_true")
parser.add_argument("--debug", action="store_true")
args = parser.parse_args()
Expand All @@ -32,39 +30,6 @@ def status(line):
print(colorama.Fore.GREEN + f">>> {line}..." + colorama.Style.RESET_ALL)


def update_po_files():
def get_current_msgids():
pot = polib.pofile("locale/en_US/LC_MESSAGES/django.po")
return {e.msgid for e in pot if not e.fuzzy and not e.obsolete}

cmd(f"git restore --staged --worktree locale")

# get the current set of msgids
saved_msgids = get_current_msgids()

# re-extract locale files from source code
ignore_paths = ("env/*", ".venv/*", "fabric/*", "media/*", "sitestatic/*", "static/*", "node_modules/*")
ignore_args = " ".join([f'--ignore="{p}"' for p in ignore_paths])

cmd(f"python manage.py makemessages -a -e haml,html,txt,py --no-location --no-wrap {ignore_args}")

# get the new set of msgids
actual_msgids = get_current_msgids()

added_msgids = actual_msgids.difference(saved_msgids)
removed_msgids = saved_msgids.difference(actual_msgids)

if DEBUG:
for mid in added_msgids:
print(f" + {repr(mid)}")
for mid in removed_msgids:
print(f" - {repr(mid)}")

# if there are no actual changes to msgids, revert
if not added_msgids and not removed_msgids:
cmd(f"git restore locale")


if __name__ == "__main__":
colorama.init()

Expand All @@ -81,13 +46,6 @@ def get_current_msgids():
status("Running isort")
cmd("isort -rc temba")

status("Updating locale PO files")
update_po_files()

if not args.skip_compilemessages:
status("Recompiling locale MO files")
cmd("python manage.py compilemessages")

# if any code changes were made, exit with error
if cmd("git diff temba locale"):
print("👎 " + colorama.Fore.RED + "Changes to be committed")
Expand Down
113 changes: 113 additions & 0 deletions temba/utils/management/commands/sync_transifex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import subprocess
import time

import requests

from django.conf import settings
from django.core.management import BaseCommand


class Command(BaseCommand):
help = "Updates the default translation and fetches other translations from Transifex"

def add_arguments(self, parser):
parser.add_argument("--token", type=str, action="store", dest="token", required=True)

def handle(self, token, *args, **kwargs):
self.extract_default_translation()

self.client = TransifexClient(token)

for lang, name in settings.LANGUAGES:
if lang != settings.DEFAULT_LANGUAGE:
self.fetch_translation(lang)

# rebuild the .mo files too
subprocess.check_output("./manage.py compilemessages", shell=True)

self.stdout.write(f"mo files updated")

def extract_default_translation(self):
"""
Extracts the default translation using makemessages
"""
ignore_paths = ("env/*", ".venv/*", "fabric/*", "media/*", "sitestatic/*", "static/*", "node_modules/*")
ignore_args = " ".join([f'--ignore="{p}"' for p in ignore_paths])
cmd = f"python manage.py makemessages -a -e haml,html,txt,py --no-location --no-wrap {ignore_args}"
subprocess.check_output(cmd, shell=True)

def fetch_translation(self, lang: str):
self.stdout.write(f"fetching translation for {lang}..")

# convert lang code to underscore format (e.g. pt-br > pt_BR)
lang = self.convert_lang_code(lang)

response = self.client.create_translation_download("rapidpro", "rapidpro", "django-po--main", lang)
download_id = response.json()["data"]["id"]

while True:
time.sleep(1)
self.stdout.write(f" > checking for download...")
response = self.client.check_download_status(download_id)

if response.status_code == 303:
self.download_translation(lang, response.headers["Location"])
break

def download_translation(self, lang: str, url: str):
self.stdout.write(f" > downloading translation...")

po_path = f"locale/{lang}/LC_MESSAGES/django.po"
response = requests.get(url)

with open(po_path, "wb") as dest:
dest.write(response.content)

self.stdout.write(f" > {po_path} updated")

def convert_lang_code(self, lang: str) -> str:
parts = lang.split("-")
if len(parts) > 1:
parts[1] = parts[1].upper()
return "_".join(parts)


class TransifexClient:
def __init__(self, token: str):
self.base_url = "https://rest.api.transifex.com/"
self.token = token

def create_translation_download(self, org: str, project: str, resource: str, lang: str):
return self._post(
f"resource_translations_async_downloads",
{
"data": {
"attributes": {
"content_encoding": "text",
"file_type": "default",
"mode": "default",
"pseudo": False,
},
"relationships": {
"language": {"data": {"id": f"l:{lang}", "type": "languages"}},
"resource": {"data": {"id": f"o:{org}:p:{project}:r:{resource}", "type": "resources"}},
},
"type": "resource_translations_async_downloads",
}
},
)

def check_download_status(self, download_id):
return self._get(f"resource_translations_async_downloads/{download_id}")

def _get(self, url):
return requests.get(
self.base_url + url, headers={"Authorization": f"Bearer {self.token}"}, allow_redirects=False
)

def _post(self, url, data):
return requests.post(
self.base_url + url,
json=data,
headers={"Content-Type": "application/vnd.api+json", "Authorization": f"Bearer {self.token}"},
)

0 comments on commit a783322

Please sign in to comment.