diff --git a/src/gui/AboutDialog.cpp b/src/gui/AboutDialog.cpp index bc3960d11..1fa50043d 100644 --- a/src/gui/AboutDialog.cpp +++ b/src/gui/AboutDialog.cpp @@ -44,29 +44,43 @@ static const QString aboutContributors = R"(
  • Sergey Vilgelm
  • Victor Engmark
  • NarwhalOfAges
  • +
  • No Name
  • +
  • SG
  • +
  • Riley Moses
  • +
  • Esteban Martinez
  • +
  • Marc Morocutti
  • +
  • Zivix
  • +
  • Benedikt Heine
  • +
  • Hugo Locurcio
  • +
  • William Petrides
  • +
  • Gunar Gessner
  • +
  • Christian Wittenhorst
  • +
  • Matt Cardarelli
  • +
  • Paul Ammann
  • +
  • Steve Isom
  • +
  • GodSpell
  • +
  • Lionel Laské
  • +
  • Daniel Epp
  • +
  • Oleksii Aleksieiev
  • +
  • Julian Stier
  • +
  • Ruben Schade
  • +
  • Bernhard
  • +
  • Wojciech Kozlowski
  • Caleb Currie
  • Morgan Courbet
  • Kyle Kneitinger
  • Chris Sohns
  • Shmavon Gazanchyan
  • xjdwc
  • -
  • Riley Moses
  • Igor Zinovik
  • Jeff
  • -
  • Esteban Martinez
  • Max Andersen
  • -
  • Zivix
  • -
  • Marc Morocutti
  • super scampy
  • -
  • Hugo Locurcio
  • -
  • Benedikt Heine
  • Mischa Peters
  • Rainer-Maria Fritsch
  • Micha Ober
  • Ivan Gromov
  • -
  • William Petrides
  • Joshua Go
  • -
  • Gunar Gessner
  • pancakeplant
  • Hans-Joachim Forker
  • Nicolas Vandemaele
  • @@ -75,30 +89,66 @@ static const QString aboutContributors = R"(
  • Mike
  • Thomas Renz
  • Toby Cline
  • -
  • Christian Wittenhorst
  • -
  • Paul Ammann
  • -
  • Matt Cardarelli
  • -
  • Steve Isom
  • Emre Dessoi
  • -
  • Wojciech Kozlowski
  • Michael Babnick
  • kernellinux
  • Patrick Evans
  • Marco
  • -
  • GodSpell
  • Jeremy Rubin
  • Korbi
  • andreas
  • Tyche's tidings
  • Daniel Kuebler
  • Brandon Corujo
  • +
  • AheroX
  • +
  • Alexandre G
  • +
  • AshinaGa
  • +
  • BYTEBOLT
  • +
  • CEH
  • +
  • Chris Stone
  • +
  • Christof Böckler
  • +
  • Claude
  • +
  • CzLer
  • +
  • Daniel Burridge
  • +
  • dark
  • +
  • Dave G
  • +
  • David Bowers
  • +
  • dickv
  • +
  • fp4
  • +
  • Huser IT Solutions GmbH
  • +
  • irf
  • +
  • Isaiah Rahmany
  • +
  • JackNYC
  • +
  • Jacob Emmert-Aronson
  • +
  • John Donadeo
  • +
  • Kosta Medinsky
  • +
  • leinad987
  • +
  • Lux
  • +
  • marek
  • +
  • mattlongname
  • +
  • mattock
  • +
  • Max Christian Pohle
  • +
  • nta/norma
  • +
  • picatsv
  • +
  • proto
  • +
  • Raymond Lau
  • +
  • Waido
  • +
  • Weinmann Willy
  • +
  • WildMage
  • + +

    VIP GitHub Sponsors:

    +

    Notable Code Contributions:

    Patreon Supporters:

    +

    GitHub Sponsors:

    +

    Translations:

    )"; diff --git a/utils/transifex_translators.py b/utils/transifex_translators.py index 9170f04ba..9fb51ce26 100644 --- a/utils/transifex_translators.py +++ b/utils/transifex_translators.py @@ -1,77 +1,70 @@ #!/usr/bin/env python3 +from collections import defaultdict import json -import os +import sys +from pathlib import Path +from urllib import request -# Download Transifex languages dump at: https://www.transifex.com/api/2/project/keepassxc/languages -# Language information from https://www.wikiwand.com/en/List_of_ISO_639-1_codes and http://www.lingoes.net/en/translator/langcode.htm +txrc = Path.home() / '.transifexrc' +if not txrc.exists(): + print('No Transifex config found. Run tx init first.') + sys.exit(1) -LANGS = { - "ar" : "العربية (Arabic)", - "bn" : "বাংলা (Bengali)", - "ca" : "català (Catalan)", - "cs" : "čeština (Czech)", - "da" : "dansk (Danish)", - "de" : "Deutsch (German)", - "el" : "ελληνικά (Greek)", - "eo" : "Esperanto (Esperanto)", - "es" : "Español (Spanish)", - "et" : "eesti (Estonian)", - "eu" : "euskara (Basque)", - "fa" : "فارسی (Farsi)", - "fa_IR" : "فارسی (Farsi (Iran))", - "fi" : "suomi (Finnish)", - "fr" : "français (French)", - "gl" : "Galego (Galician)", - "he" : "עברית (Hebrew)", - "hr_HR" : "hrvatski jezik (Croatian)", - "hu" : "magyar (Hungarian)", - "id" : "Bahasa Indonesia (Indonesian)", - "is_IS" : "Íslenska (Icelandic)", - "it" : "Italiano (Italian)", - "ja" : "日本語 (Japanese)", - "kk" : "қазақ тілі (Kazakh)", - "ko" : "한국어 (Korean)", - "la" : "latine (Latin)", - "lt" : "lietuvių kalba (Lithuanian)", - "lv" : "latviešu valoda (Latvian)", - "nb" : "Norsk Bokmål (Norwegian Bokmål)", - "nl_NL" : "Nederlands (Dutch)", - "my" : "ဗမာစာ (Burmese)", - "pa" : "ਪੰਜਾਬੀ (Punjabi)", - "pa_IN" : "ਪੰਜਾਬੀ (Punjabi (India))", - "pl" : "język polski (Polish)", - "pt" : "Português (Portuguese)", - "pt_BR" : "Português (Portuguese (Brazil))", - "pt_PT" : "Português (Portuguese (Portugal))", - "ro" : "Română (Romanian)", - "ru" : "русский (Russian)", - "sk" : "Slovenčina (Slovak)", - "sl_SI" : "Slovenščina (Slovenian)", - "sr" : "српски језик (Serbian)", - "sv" : "Svenska (Swedish)", - "th" : "ไทย (Thai)", - "tr" : "Türkçe (Turkish)", - "uk" : "Українська (Ukrainian)", - "zh_CN" : "中文 (Chinese (Simplified))", - "zh_TW" : "中文 (台灣) (Chinese (Traditional))", -} +org = 'o:keepassxc' +proj = f'{org}:p:keepassxc' +resource = f'{proj}:r:share-translations-keepassxc-en-ts--master' +token = [l for l in open(txrc, 'r') if l.startswith('token')][0].split('=', 1)[1].strip() +member_blacklist = ['u:droidmonkey', 'u:phoerious'] -TEMPLATE = "
  • {0}: {1}
  • \n" -if not os.path.exists("languages.json"): - print("Could not find 'languages.json' in current directory!") - print("Save the output from https://www.transifex.com/api/2/project/keepassxc/languages") - exit(0) +def get_url(url): + req = request.Request(url) + req.add_header('Content-Type', 'application/vnd.api+json') + req.add_header('Authorization', f'Bearer {token}') + with request.urlopen(req) as resp: + return json.load(resp) -with open("languages.json") as json_file: - output = open("translators.html", "w", encoding="utf-8") - languages = json.load(json_file) - for lang in languages: - code = lang["language_code"] - if code not in LANGS: - print("WARNING: Could not find language code:", code) - continue - translators = ", ".join(sorted(lang["reviewers"] + lang["translators"], key=str.casefold)) - output.write(TEMPLATE.format(LANGS[code], translators)) - output.close() - print("Language translators written to 'translators.html'!") \ No newline at end of file + +print('Fetching languages...', file=sys.stderr) +languages_json = get_url(f'https://rest.api.transifex.com/projects/{proj}/languages') +languages = {} +for lang in languages_json['data']: + languages[lang['id']] = lang['attributes']['name'] + +print('Fetching language stats...', file=sys.stderr) +language_stats_json = get_url('https://rest.api.transifex.com/resource_language_stats?' + f'filter[project]={proj}&filter[resource]={resource}') +completion = {} +for stat in language_stats_json['data']: + completion = stat['attributes']['translated_strings'] / stat['attributes']['total_strings'] + if completion < .6: + languages.pop(stat['relationships']['language']['data']['id']) + +print('Fetching language members...', end='', file=sys.stderr) +members_json = get_url(f'https://rest.api.transifex.com/team_memberships?filter[organization]={org}') +members = defaultdict(set) +for member in members_json['data']: + print('.', end='', file=sys.stderr) + if member['relationships']['user']['data']['id'] in member_blacklist: + continue + lid = member['relationships']['language']['data']['id'] + if lid not in languages: + continue + user = get_url(member['relationships']['user']['links']['related'])['data']['attributes']['username'] + members[lid].add(user) +print(file=sys.stderr) + +print('')