Exemple #1
0
def pull(config, languages=None):
    """
    Pulls translations from the POEditor API.
    """
    assert config
    client = POEditorAPI(api_token=config.get("main", "apikey"))
    sections = config.sections()

    for s in sections:
        if s.startswith("project."):
            print("\nProject: {}".format(s))
            project_id = config.get(s, "project_id")
            file_type = config.get(s, "type")
            options = config.options(s)

            for o in options:
                if o.startswith("trans."):
                    language = o[6:]
                    if languages and language not in languages:
                        continue

                    export_path = config.get(s, o)
                    parent_dir = os.path.dirname(export_path)
                    if not os.path.exists(parent_dir):
                        os.makedirs(parent_dir)

                    print("Language: {}".format(language))
                    client.export(project_id, language_code=language, file_type=file_type, local_file=export_path)
Exemple #2
0
def status(config):
    """
    Status is a simple task that displays the existing project configuration in a more human readable format.
    It lists all resources that have been initialized under the local project and all their associated translation
    files.
    """
    assert config
    client = POEditorAPI(api_token=config.get("main", "apikey"))
    sections = config.sections()

    print("Api key: {}".format(config.get("main", "apikey")))

    for s in sections:
        if s.startswith("project."):
            project_id = config.get(s, "project_id")
            details = client.view_project_details(project_id)
            terms = config.get(s, 'terms', None) if config.has_option(s, 'terms') else None
            options = config.options(s)

            print("\nProject: {0} ({1})".format(details['name'], details['id']))
            print("Terms: {0}".format(terms))

            for option in options:
                if option.startswith("trans."):
                    import_path = config.get(s, option)
                    language = option.split('.', 1)[-1]
                    print(" - Language {0}: {1}".format(language, import_path))
Exemple #3
0
def download_translation(file_path, project_id, api_token):
    client = POEditorAPI(api_token=api_token)

    os.makedirs(Path(file_path).absolute().parent, exist_ok=True)

    client.export(
        project_id=project_id,
        language_code='fr',
        file_type='mo',
        local_file=file_path,
    )
Exemple #4
0
def pushTerms(config):
    """
    Pushes new terms to POEditor
    """
    assert config
    client = POEditorAPI(api_token=config.get("main", "apikey"))
    sections = config.sections()

    for s in sections:
        if s.startswith("project."):
            terms = config.get(s, 'terms', None) if config.has_option(s, 'terms') else None
            if terms:
                project_id = config.get(s, "project_id")
                print(" - Project: {0}, {1}\n".format(s, terms))
                client.update_terms(project_id, terms)
Exemple #5
0
def main(api_token, project_id, languages, tags, file_path, header_comment):
    client = POEditorAPI(api_token)
    # See also: https://github.com/sporteasy/python-poeditor/pull/15
    client.FILTER_BY += 'proofread'
    done = 0
    lock = threading.Lock()

    def export_worker(params):
        ((language_code, language_id), (tag, module)) = params
        output = file_path.format(language_id, module)
        (_, temp) = client.export(project_id, language_code, 'android_strings',
                                  'proofread', tag)
        try:
            if os.path.getsize(temp) > 0:
                try:
                    os.makedirs(os.path.dirname(output))
                except FileExistsError:
                    pass
                with open(output, 'w') as writer:
                    with open(temp) as reader:
                        head = reader.readline()
                        assert head.startswith('<?xml')
                        writer.write(head)
                        writer.write(header_comment)
                        for line in reader:
                            writer.write(line)
        finally:
            os.remove(temp)
        with lock:
            nonlocal done
            done += 1
            print("{}/{}: {}".format(done, len(languages) * len(tags), output))

    pool = ThreadPool(max(64, multiprocessing.cpu_count()))
    pool.map(export_worker, itertools.product(languages.items(), tags.items()))
Exemple #6
0
def pushTerms(config):
    """
    Pushes new terms to POEditor
    """
    assert config
    client = POEditorAPI(api_token=config.get("main", "apikey"))
    sections = config.sections()

    for s in sections:
        if s.startswith("project."):
            terms = config.get(s, 'terms', None) if config.has_option(
                s, 'terms') else None
            if terms:
                project_id = config.get(s, "project_id")
                print(" - Project: {0}, {1}\n".format(s, terms))
                client.update_terms(project_id, terms)
Exemple #7
0
def push(config, languages=None, overwrite=False, sync_terms=False):
    """
    Push terms and languages
    """
    assert config
    client = POEditorAPI(api_token=config.get("main", "apikey"))
    sections = config.sections()
    sleep_time = 32
    for section in sections:
        if not section.startswith("project."):
            continue

        print("Project: {}".format(section))
        project_id = config.get(section, "project_id")
        options = config.options(section)

        for option in options:
            if option.startswith("trans."):
                import_path = config.get(section, option)
                language = option.split('.', 1)[-1]
                if languages and language not in languages:
                    continue

                if not os.path.exists(import_path):
                    print("Error: {path} doesn't exist: ignoring language '{language}'"
                          .format(path=import_path, language=language))
                    continue
                print("    Pushing language '{}'...".format(language))
                for i in xrange(0, 100):
                    try:
                        client.update_terms_definitions(
                            project_id,
                            language_code=language,
                            file_path=import_path,
                            overwrite=overwrite,
                            sync_terms=sync_terms
                        )
                        print("language {} ok ".format(language))
                        break
                    except Exception as e:
                        if hasattr(e, 'error_code') and e.error_code == u'4048': #NOQA
                            print("    error 4048 rety-Pushing {} in {}s language '{}'...".format(i+1, sleep_time, language)) #NOQA
                            time.sleep(sleep_time)
                            sleep_time = int(sleep_time + 1)
                            continue
Exemple #8
0
def init(config):
    """
    Initializes the project on POEditor based on the configuration file.
    """
    assert config
    client = POEditorAPI(api_token=config.get("main", "apikey"))
    sections = config.sections()

    for s in sections:
        if s.startswith("project."):
            print(" - Project: {}".format(s))
            project_id = config.get(s, "project_id")

            # 1. Push terms
            terms = config.get(s, 'terms', None) if config.has_option(
                s, 'terms') else None
            if terms:
                project_id = config.get(s, "project_id")
                print(" - Terms: {0}".format(terms))
                client.update_terms(project_id, terms)

            # 2. Create/add languages
            options = config.options(s)
            for o in options:
                if o.startswith("trans."):
                    lang = o[6:]

                    try:
                        client.add_language_to_project(project_id, lang)
                    except POEditorException:
                        pass

                    client.update_definitions(project_id=project_id,
                                              file_path=config.get(s, o),
                                              language_code=lang,
                                              overwrite=True)
                    print(" - Language added: {}".format(lang))
def main(api_token, project_id, languages, tags, file_path):
    client = POEditorAPI(api_token)
    # See also: https://github.com/sporteasy/python-poeditor/pull/15
    client.FILTER_BY += 'proofread'
    done = 0
    lock = threading.Lock()

    def export_worker(params):
        ((language_code, language_id), (tag, module)) = params
        output = file_path.format(language_id, module)
        try:
            os.makedirs(os.path.dirname(output))
        except FileExistsError:
            pass
        client.export(project_id, language_code, 'android_strings',
                      'proofread', tag, output)
        with lock:
            nonlocal done
            done += 1
            print("{}/{}: {}".format(done, len(languages) * len(tags), output))

    pool = ThreadPool(max(64, multiprocessing.cpu_count()))
    pool.map(export_worker, itertools.product(languages.items(), tags.items()))
Exemple #10
0
def init(config):
    """
    Initializes the project on POEditor based on the configuration file.
    """
    assert config
    client = POEditorAPI(api_token=config.get("main", "apikey"))
    sections = config.sections()

    for s in sections:
        if s.startswith("project."):
            print(" - Project: {}".format(s))
            project_id = config.get(s, "project_id")

            # 1. Push terms
            terms = config.get(s, 'terms', None) if config.has_option(s, 'terms') else None
            if terms:
                project_id = config.get(s, "project_id")
                print(" - Terms: {0}".format(terms))
                client.update_terms(project_id, terms)

            # 2. Create/add languages
            options = config.options(s)
            for o in options:
                if o.startswith("trans."):
                    lang = o[6:]

                    try:
                        client.add_language_to_project(project_id, lang)
                    except POEditorException:
                        pass

                    client.update_definitions(
                        project_id=project_id,
                        file_path=config.get(s, o),
                        language_code=lang,
                        overwrite=True
                    )
                    print(" - Language added: {}".format(lang))
Exemple #11
0
#!/usr/bin/env python3
import os

from dotenv import load_dotenv
from poeditor import POEditorAPI

os.chdir(os.path.dirname(os.path.realpath(__file__)))
load_dotenv()

mo_dir = "../i18n/mo"
po_dir = "../i18n/po"

if not os.path.isdir(mo_dir):
    os.mkdir(mo_dir)

if not os.path.isdir(po_dir):
    os.mkdir(po_dir)

client = POEditorAPI(os.getenv("POEDITOR_TOKEN"))
projects = client.list_projects()
project_id = [proj for proj in projects if proj["name"] == "WinDynamicDesktop"][0]["id"]
languages = client.list_project_languages(project_id)
language_codes = [lang["code"] for lang in languages if lang["percentage"] >= 50]

for lc in language_codes:
    print(f"Downloading translation for {lc}")
    client.export(project_id, lc, "po", local_file=f"{po_dir}/{lc}.po")
    client.export(project_id, lc, "mo", local_file=f"{mo_dir}/{lc}.mo")
Exemple #12
0
import os
from poeditor import POEditorAPI

project_id = os.environ['POEDITOR_PROJECT_ID']
api_token = os.environ['POEDITOR_API_TOKEN']
client = POEditorAPI(api_token=api_token)

project = client.view_project_details(project_id)
print(f"Before update, {project['name']} (id: {project['id']}) has {project['terms']} terms.")

update_results = client.update_terms(
    project_id=project_id,
    file_path='_build/docs.pot',
    sync_terms=True,
)

terms = update_results['terms']
print("Terms updated:")
for k, v in terms.items():
    print(f"\t{k}: {v}")


project = client.view_project_details(project_id)
print(f"After update, {project['name']} (id: {project['id']}) has {project['terms']} terms.")
Exemple #13
0
import os
import json
import subprocess
from poeditor import POEditorAPI
from settings import PO_API_KEY, PROJECT_ID

client = POEditorAPI(api_token=PO_API_KEY)

languages = client.list_project_languages(PROJECT_ID)

language_codes = []

for l in languages:
    if l['percentage'] > 50:
        language_codes.append(l['code'])

for code in language_codes:
    print(f"Downloading {code}...")
    client.export(PROJECT_ID,
                  code,
                  file_type='json',
                  local_file=f'lib/l10n/intl_{code}.json')
    print(f"Downloaded {code}")

for fname in os.listdir('lib/l10n'):
    if fname.endswith('.json'):
        fname = f'lib/l10n/{fname}'
        out_file = fname.replace(".json", ".arb")
        ret = {}
        with open(fname) as json_file:
            data = json.load(json_file)
Exemple #14
0
import os

from poeditor import POEditorAPI

if not os.path.isdir("mo"):
    os.mkdir("mo")

if not os.path.isdir("po"):
    os.mkdir("po")

with open("poeditor_token", 'r') as fileobj:
    api_token = fileobj.readline().strip()

client = POEditorAPI(api_token)
projects = client.list_projects()
project_id = [p for p in projects if p["name"] == "WinDynamicDesktop"][0]["id"]
languages = client.list_project_languages(project_id)
language_codes = [l["code"] for l in languages if l["translations"]]

for lc in language_codes:
    print(f"Downloading translation for {lc}")
    client.export(project_id, lc, "po", local_file=f"po/{lc}.po")
    client.export(project_id, lc, "mo", local_file=f"mo/{lc}.mo")
Exemple #15
0
from pathlib import Path
import json
from babel.core import Locale
from poeditor import POEditorAPI

path_cwd = Path.cwd()

with path_cwd.joinpath("script/poediter.json").open("r") as fp:
    args = json.load(fp)

poe = POEditorAPI(args["api_token"])
domain = "py_sms_impl"

for code in map(lambda d: d["code"], poe.list_project_languages(args["id"])):
    loc_ins = Locale.parse(code, sep="-")
    dist_path = path_cwd / "locale" / str(loc_ins) / "LC_MESSAGES/py_sms_impl.po"
    poe.export(args["id"], code, local_file=str(dist_path))
    print("Downloaded: %s" % dist_path)
Exemple #16
0
def cmd_poeditor_sync(args):
    opts = env.core.options.with_prefix('locale.poeditor')

    if 'project_id' not in opts:
        raise RuntimeError("POEditor project ID isn't set!")
    poeditor_project_id = opts['project_id']

    if 'api_token' not in opts:
        raise RuntimeError("POEditor API token isn't set!")
    poeditor_api_token = opts['api_token']

    client = POEditorAPI(api_token=poeditor_api_token)

    # Package versions are stored as part of the project's description in the POEditor
    description = POEditorDescription(client, poeditor_project_id)
    local_ver = pkginfo.packages[args.package].version
    if args.package in description.packages:
        remote_ver = description.packages[args.package]

        if pkg_version.parse(local_ver) < pkg_version.parse(remote_ver):
            raise RuntimeError(
                "Version of the '%s' package must be not lower than %s in order to use translations from the POEditor "
                "(current version: %s)." %
                (args.package, remote_ver, local_ver))

    # Update local po-files
    poeditor_terms = {}
    reference_catalogs = {}
    for comp_id, locales in components_and_locales(args,
                                                   work_in_progress=True):
        cmd_update(
            Namespace(package=pkginfo.comp_pkg(comp_id),
                      component=[
                          comp_id,
                      ],
                      locale=[lc for lc in locales if lc != 'ru'],
                      extract=args.extract,
                      force=False))

        for locale in locales:
            if locale == 'ru' and locales != ['ru']:
                po_path = catalog_filename(comp_id, locale)
                if po_path.exists():
                    ref_catalog = reference_catalogs.get(locale)
                    if ref_catalog is None:
                        ref_catalog = Catalog(locale=locale)
                        reference_catalogs[locale] = ref_catalog
                    with po_path.open('r') as po_fd:
                        for m in read_po(po_fd, locale=locale):
                            m.context = comp_id
                            ref_catalog[m.id] = m
                continue

            terms = poeditor_terms.get(locale)
            if not terms:
                logger.debug(
                    "Fetching translations from POEditor for locale [%s]...",
                    locale)
                language_code = locale.replace('_', '-').lower()
                terms = client.view_project_terms(poeditor_project_id,
                                                  language_code=language_code)
                poeditor_terms[locale] = terms

            # Filter terms by context
            terms = [term for term in terms if comp_id == term['context']]

            po_path = catalog_filename(comp_id, locale)

            if not po_path.exists():
                continue

            with po_path.open('r') as po_fd:
                po = read_po(po_fd, locale=locale)

            updated = 0

            for msg in po:
                for term in terms:
                    if msg.id == term['term']:
                        cur_tr = msg.string
                        new_tr = term['translation']['content']

                        if cur_tr != new_tr:
                            msg.string = new_tr
                            updated += 1

                        break

            if updated != 0:
                with io.open(po_path, 'wb') as fd:
                    write_po(fd, po, width=80, omit_header=True)

                logger.info(
                    "%d messages translated for component [%s] locale [%s]",
                    updated, comp_id, locale)

    # Synchronize terms
    remote_terms = defaultdict(set)
    target_state = defaultdict(dict)

    for item in client.view_project_terms(poeditor_project_id):
        remote_terms[item['term']].add(item['context'])

    comps = []
    for comp_id, _ in components_and_locales(args, work_in_progress=True):
        pot_path = catalog_filename(comp_id, '', ext='pot')
        with pot_path.open('r') as fd:
            pot = read_po(fd)
        for msg in pot:
            if msg.id == '':
                continue
            target_state[msg.id][comp_id] = True
        comps.append(comp_id)

    for comp_id in comps:
        for msg_id in target_state:
            if comp_id not in target_state[msg_id]:
                target_state[msg_id][comp_id] = False

    terms_to_add = []
    terms_to_del = []
    for msg_id in target_state:
        if msg_id not in remote_terms:
            for comp_id in target_state[msg_id]:
                if target_state[msg_id][comp_id]:
                    logger.debug("ADD (%s, %s)", comp_id, msg_id)
                    terms_to_add.append(dict(term=msg_id, context=comp_id))
            continue

        for comp_id in target_state[msg_id]:
            if target_state[msg_id][comp_id] and comp_id not in remote_terms[
                    msg_id]:
                logger.debug("ADD (%s, %s)", comp_id, msg_id)
                terms_to_add.append(dict(term=msg_id, context=comp_id))
            if not target_state[msg_id][comp_id] and comp_id in remote_terms[
                    msg_id]:
                logger.debug("DEL (%s, %s)", comp_id, msg_id)
                terms_to_del.append(dict(term=msg_id, context=comp_id))

    for msg_id, contexts in remote_terms.items():
        if msg_id not in target_state:
            for comp_id in contexts:
                if comp_id in comps:
                    logger.debug("DEL (%s, %s)", comp_id, msg_id)
                    terms_to_del.append(dict(term=msg_id, context=comp_id))

    if len(terms_to_add) > 0 and args.no_dry_run:
        client.add_terms(poeditor_project_id, terms_to_add)
    logger.info("%d messages added to the POEditor", len(terms_to_add))

    if len(terms_to_del) > 0 and args.no_dry_run:
        client.delete_terms(poeditor_project_id, terms_to_del)
    logger.info("%d messages deleted from the POEditor", len(terms_to_del))

    if len(reference_catalogs) > 0:
        logger.info(
            "Upload the following reference translations to POEditor: " +
            ", ".join(reference_catalogs.keys()))
        if args.no_dry_run:
            wait_for_rate_limit = False
            for locale, catalog in reference_catalogs.items():
                with NamedTemporaryFile(suffix='.po') as fd:
                    write_po(fd, catalog, width=80, omit_header=True)
                    fd.flush()
                    logger.debug("Uploading %s reference translation...",
                                 locale)

                    # Free account allows doing 1 upload per 20 seconds
                    sleep(20 if wait_for_rate_limit else 0)
                    wait_for_rate_limit = True

                    client.update_terms_translations(
                        project_id=poeditor_project_id,
                        language_code=locale.replace('-', '_'),
                        overwrite=True,
                        sync_terms=False,
                        file_path=fd.name)

    if len(terms_to_add) > 0 or len(terms_to_del) > 0:
        if args.no_dry_run:
            description.update(args.package, local_ver)
        logger.info("Set '%s' package version to %s in the POEditor.",
                    args.package, local_ver)