locale: gui: show translation completion percentage in language names

In the GUIs, on the language-select screen, show e.g.
  Czech (100%), Danish (13%), Dutch (54%)
instead of
  Czech, Danish, Dutch

- we count the source strings when creating the .pot PO-template file
  and add an "X-Electrum-SourceStringCount" header to it, in the push_locale.py script that uploads the .pot file to crowdin.
  - later, when we run electrum-locale/update.py to download the translations in .po files, these files will also contain the same header.
  - then when the build_locale.sh script compiles those .po files, we can read the header and use it to populate a new "stats.json" file
    that we place in electrum/locale/locale/ and bundle in the all release binaries/distributables.
    - stats.json also includes the number of translated strings for each lang
- at runtime we simply read stats.json and use the values to calculate the percentages
  - a prior implementation did not pre-calc stats.json but did all calculations at runtime (by opening all .mo translations)
    - however that was deemed to slow, hence the build-time pre-calc
      - runtime calc took 40 ms on my laptop, so I guess it could easily take 10x that on an old phone
- just as we have always been very tolerant of any locale files or even the whole locale/ dir missing, we also tolerate stats.json missing
This commit is contained in:
SomberNight
2026-02-16 00:47:47 +00:00
parent 6de3fef717
commit 3afa2fcdf3
6 changed files with 154 additions and 12 deletions
+5 -8
View File
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QRegularExpression
from electrum.bitcoin import TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
from electrum.i18n import set_language, languages
from electrum.i18n import set_language, get_gui_lang_names
from electrum.logging import get_logger
from electrum.util import base_unit_name_to_decimal_point
from electrum.gui import messages
@@ -52,7 +52,7 @@ class QEConfig(AuthMixin, QObject):
@language.setter
def language(self, language):
if language not in languages:
if language not in get_gui_lang_names():
return
if self.config.LOCALIZATION_LANGUAGE != language:
self.config.LOCALIZATION_LANGUAGE = language
@@ -62,12 +62,9 @@ class QEConfig(AuthMixin, QObject):
languagesChanged = pyqtSignal()
@pyqtProperty('QVariantList', notify=languagesChanged)
def languagesAvailable(self):
# sort on translated languages, then re-add Default on top
langs = copy.deepcopy(languages)
default = langs.pop('')
langs_sorted = sorted(list(map(lambda x: {'value': x[0], 'text': x[1]}, langs.items())), key=lambda x: x['text'])
langs_sorted.insert(0, {'value': '', 'text': default})
return langs_sorted
langs = get_gui_lang_names()
langs_list = list(map(lambda x: {'value': x[0], 'text': x[1]}, langs.items()))
return langs_list
termsOfUseChanged = pyqtSignal()
@pyqtProperty(bool, notify=termsOfUseChanged)