# This file is part of Beremiz
# Copyright (C) 2021: Edouard TISSERANT
# See COPYING file for copyrights details.
from __future__ import absolute_import
# to have it for python 2, had to install
# https://pypi.org/project/pycountry/18.12.8/
# python2 -m pip install pycountry==18.12.8 --user
cmd_parser = re.compile(r'(?:"([^"]+)"\s*|([^\s]+)\s*)?')
""" Opens PO file with POEdit """
if sys.platform.startswith('win'):
from six.moves import winreg
poedit_cmd = winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE,
'SOFTWARE\\Classes\\poedit\\shell\\open\\command')
cmd = re.findall(cmd_parser, poedit_cmd)
dblquote_value,smpl_value = cmd[0]
poedit_path = dblquote_value+smpl_value
poedit_path = subprocess.check_output("command -v poedit", shell=True).strip()
except subprocess.CalledProcessError:
wx.MessageBox("POEdit is not found or installed !")
subprocess.Popen([poedit_path,pofile])
def EtreeToMessages(msgs):
""" Converts XML tree from 'extract_i18n' templates into a list of tuples """
"\n".join([line.text for line in msg]),
msg.get("label"), msg.get("id")))
def SaveCatalog(fname, messages):
""" Save messages given as list of tupple (msg,label,id) in POT file """
w.ImportMessages(messages)
with open(fname, 'w') as POT_file:
po_files = [fname for fname in os.listdir(dirpath) if fname.endswith(".po")]
return [(po_fname[:-3],os.path.join(dirpath, po_fname)) for po_fname in po_files]
def ReadTranslations(dirpath):
""" Read all PO files from a directory and return a list of (langcode, translation_dict) tuples """
for translation_name, po_path in GetPoFiles(dirpath):
with open(po_path, 'r') as PO_file:
translations.append((translation_name, r.get_messages()))
def MatchTranslations(translations, messages, errcallback):
Matches translations against original message catalog,
warn about inconsistancies,
returns list of langs, and a list of (msgid, [translations]) tuples
for msgid,label,svgid in messages:
for langcode,translation in translations:
msg = translation.pop(msgid, None)
broken_lang.add(langcode)
errcallback(_('{}: Missing translation for "{}" (label:{}, id:{})\n').format(langcode,msgid,label,svgid))
translated_message.append(msgid)
translated_message.append(msg)
translated_messages.append((msgid,translated_message))
for langcode,translation in translations:
l,c = langcode.split("_")
language_name = pycountry.languages.get(alpha_2 = l).name
country_name = pycountry.countries.get(alpha_2 = c).name
langname = "{} ({})".format(language_name, country_name)
langname = pycountry.languages.get(alpha_2 = langcode).name
langs.append((langname,langcode))
for msgid, msg in translation.iteritems():
errcallback(_('{}: Unused translation "{}":"{}"\n').format(langcode,msgid,msg))
if broken or langcode in broken_lang:
errcallback(_('Translation for {} is outdated, please edit {}.po, click "Catalog -> Update from POT File..." and select messages.pot.\n').format(langcode,langcode))
return langs,translated_messages
def TranslationToEtree(langs,translated_messages):
result = etree.Element("translations")
langsroot = etree.SubElement(result, "langs")
langel = etree.SubElement(langsroot, "lang", {"code":code})
msgsroot = etree.SubElement(result, "messages")
for msgid, msgs in translated_messages:
msgidel = etree.SubElement(msgsroot, "msgid")
msgel = etree.SubElement(msgidel, "msg")
for line in msg.split("\n"):
lineel = etree.SubElement(msgel, "line")
lineel.text = escape(line.encode("utf-8")).decode("utf-8")
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
"Project-Id-Version: PACKAGE VERSION\\n"
"POT-Creation-Date: %(time)s\\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
"Language-Team: LANGUAGE <LL@li.org>\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"Generated-By: SVGHMI 1.0\\n"
def make_escapes(pass_iso8859):
escapes = [chr(i) for i in range(256)]
# Allow iso-8859 characters to pass through so that e.g. 'msgid
# "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we
# escape any character outside the 32..126 range.
escapes[i] = "\\%03o" % i
escapes[ord('\\')] = '\\\\'
escapes[ord('\t')] = '\\t'
escapes[ord('\r')] = '\\r'
escapes[ord('\n')] = '\\n'
escapes[ord('\"')] = '\\"'
make_escapes(pass_iso8859 = True)
s[i] = escapes[ord(s[i])]
return EMPTYSTRING.join(s)
# This converts the various Python string types into a format that is
# appropriate for .po files, namely much closer to C style.
s = '"' + escape(s) + '"'
lines[-1] = lines[-1] + '\n'
for i in range(len(lines)):
lines[i] = escape(lines[i])
s = '""\n"' + lineterm.join(lines) + '"'
def ImportMessages(self, msgs):
for msg, label, svgid in msgs:
self.addentry(msg.encode("utf-8"), label, svgid)
def addentry(self, msg, label, svgid):
self.__messages.setdefault(msg, set()).add(entry)
timestamp = time.strftime('%Y-%m-%d %H:%M+%Z')
print >> fp, pot_header % {'time': timestamp}
for k, v in self.__messages.items():
reverse.setdefault(tuple(keys), []).append((k, v))
d = {'label': label, 'svgid': svgid}
s = _(' %(label)s:%(svgid)s') % d
if len(locline) + len(s) <= 78:
if len(locline) > len(locpfx):
print >> fp, 'msgid', normalize(k)
print >> fp, 'msgstr ""\n'
def add(self, msgid, msgstr, fuzzy):
"Add a non-fuzzy translation to the dictionary."
if not fuzzy and msgstr and msgid:
self.__messages[msgid.decode('utf-8')] = msgstr.decode('utf-8')
# If we get a comment line after a msgstr, this is a new entry
if l[0] == '#' and section == STR:
self.add(msgid, msgstr, fuzzy)
if l[:2] == '#,' and 'fuzzy' in l:
# Now we are in a msgid section, output previous section
if l.startswith('msgid') and not l.startswith('msgid_plural'):
self.add(msgid, msgstr, fuzzy)
# This is a message with plural forms
elif l.startswith('msgid_plural'):
print >> sys.stderr, 'msgid_plural not preceded by msgid on %s:%d' %\
msgid += '\0' # separator of singular and plural
# Now we are in a msgstr section
elif l.startswith('msgstr'):
if l.startswith('msgstr['):
print >> sys.stderr, 'plural without msgid_plural on %s:%d' %\
msgstr += '\0' # Separator of the various plural forms
print >> sys.stderr, 'indexed msgstr required for plural on %s:%d' %\
print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \
self.add(msgid, msgstr, fuzzy)