translations: more validations, ensure named placeholders match
This commit is contained in:
parent
3a8f6a0953
commit
dc6f333fae
|
@ -286,7 +286,7 @@ msgstr "تعبير الوظيفة المجدولة غير صحيح '%s'"
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr "من فضلك أضف المورد %(resource)s إلى الدليل %(config_resource)"
|
msgstr "من فضلك أضف المورد %(resource)s إلى الدليل %(config_resource)s"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -287,7 +287,7 @@ msgstr "Ugyldigt cron-udtryk '%s'"
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr "Tilføj ressource %(ressource)s til %(config_resource)s bibliotek"
|
msgstr "Tilføj ressource %(resource)s til %(config_resource)s bibliotek"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -285,7 +285,7 @@ msgstr ""
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Kérem adja hozzá a(z) %(resource) erőforrást a %(config_resource) könyvtárhoz"
|
"Kérem adja hozzá a(z) %(resource)s erőforrást a %(config_resource)s könyvtárhoz"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -293,7 +293,7 @@ msgstr "Espressione cron non valida '%s'"
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Aggiungi la/le risorse %(resource) nella/e cartella/e %(config_resource)"
|
"Aggiungi la/le risorse %(resource)s nella/e cartella/e %(config_resource)s"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -292,7 +292,7 @@ msgstr "A expressão cron '%s' é inválida"
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr "Adicionar o recurso %(resource)s à pasta %(config_resources)s"
|
msgstr "Adicionar o recurso %(resource)s à pasta %(config_resource)s"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -294,7 +294,7 @@ msgstr "A expressão de cron '%s' é inválida"
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Por favor, adicione o recurso %(resource)s para a diretoria "
|
"Por favor, adicione o recurso %(resource)s para a diretoria "
|
||||||
"%(config_resources)s"
|
"%(config_resource)s"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -290,7 +290,7 @@ msgstr "Недопустимое выражение cron '%s'"
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr "Пожалуйста, добавьте источник %(resource)s в папку %(config_resource)"
|
msgstr "Пожалуйста, добавьте источник %(resource)s в папку %(config_resource)s"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -289,7 +289,7 @@ msgstr "Biểu thức cron '%s' không hợp lệ"
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr "Vui lòng thêm tài nguyên %(resource) vào thư mục %(config_resource)"
|
msgstr "Vui lòng thêm tài nguyên %(resource)s vào thư mục %(config_resource)s"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -287,7 +287,7 @@ msgstr "无效的 cron 正则表达式 '%s'"
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr "请将资源 %(resource) 添加到 %(config_resource) 目录"
|
msgstr "请将资源 %(resource)s 添加到 %(config_resource)s 目录"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
|
@ -284,7 +284,7 @@ msgstr "無效的 cron 表述式 '%s'"
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||||
msgstr "請將資源 %(resource)s 加入至 %(config_resource) 的路徑"
|
msgstr "請將資源 %(resource)s 加入至 %(config_resource)s 的路徑"
|
||||||
|
|
||||||
# Settings dialog
|
# Settings dialog
|
||||||
msgid "New Break"
|
msgid "New Break"
|
||||||
|
|
108
validate_po.py
108
validate_po.py
|
@ -23,24 +23,84 @@ import polib
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def has_equal_placeholders(left: str, right: str) -> bool:
|
def validate_placeholders(message: str) -> bool:
|
||||||
percents = re.finditer(r'%(?P<name>\(\w+\))?(?P<format>[a-z])', left)
|
pos = 0
|
||||||
|
|
||||||
unnamed = defaultdict(int)
|
success = True
|
||||||
named = []
|
|
||||||
for percent in percents:
|
count_placeholders = 0
|
||||||
if percent.group('name'):
|
count_unnamed = 0
|
||||||
named.append(f"%({percent.group('name')}){percent.group('format')}")
|
|
||||||
else:
|
while True:
|
||||||
match = f"%{percent.group('format')}"
|
index = message.find("%", pos)
|
||||||
unnamed[match] += 1
|
if index == -1:
|
||||||
|
break
|
||||||
|
|
||||||
|
pos = index + 1
|
||||||
|
|
||||||
|
nextchar = message[pos : pos + 1]
|
||||||
|
|
||||||
|
name = None
|
||||||
|
|
||||||
|
if nextchar == "(":
|
||||||
|
index = message.find(")", pos)
|
||||||
|
if index == -1:
|
||||||
|
success = False
|
||||||
|
print(f"Unclosed parenthetical in '{message}'")
|
||||||
|
break
|
||||||
|
name = message[pos + 1 : index]
|
||||||
|
|
||||||
|
pos = index + 1
|
||||||
|
|
||||||
|
nextchar = message[pos : pos + 1]
|
||||||
|
if nextchar not in ["%", "s", "d", "i", "f", "F"]:
|
||||||
|
success = False
|
||||||
|
print(f"Invalid format modifier in '{message}'")
|
||||||
|
break
|
||||||
|
|
||||||
|
if nextchar != "%":
|
||||||
|
count_placeholders += 1
|
||||||
|
if name is None:
|
||||||
|
count_unnamed += 1
|
||||||
|
|
||||||
|
pos += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
if count_unnamed > 1:
|
||||||
|
success = False
|
||||||
|
print(f"Multiple unnamed placeholders in '{message}'")
|
||||||
|
|
||||||
|
if count_unnamed > 0 and count_placeholders > count_unnamed:
|
||||||
|
success = False
|
||||||
|
print(f"Mixing named and unnamed placeholders in '{message}'")
|
||||||
|
|
||||||
|
return success
|
||||||
|
|
||||||
|
def has_equal_placeholders(left: str, right: str) -> bool:
|
||||||
|
def _get_placeholders(message: str) -> tuple:
|
||||||
|
percents = re.finditer(r"%(?P<name>\(\w+\))?(?P<format>[a-z])", message)
|
||||||
|
|
||||||
|
unnamed = defaultdict(int)
|
||||||
|
named = set()
|
||||||
|
for percent in percents:
|
||||||
|
if percent.group("name"):
|
||||||
|
named.add(f"%({percent.group('name')}){percent.group('format')}")
|
||||||
|
else:
|
||||||
|
match = f"%{percent.group('format')}"
|
||||||
|
unnamed[match] += 1
|
||||||
|
return (unnamed, named)
|
||||||
|
|
||||||
|
(left_unnamed, left_named) = _get_placeholders(left)
|
||||||
|
(right_unnamed, right_named) = _get_placeholders(right)
|
||||||
|
|
||||||
# count unnamed cases (eg. %s, %d)
|
# count unnamed cases (eg. %s, %d)
|
||||||
for match, count in unnamed.items():
|
for match, count in left_unnamed.items():
|
||||||
if right.count(match) != count:
|
if right_unnamed.get(match, 0) != count:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# no need to count named cases - they are optional
|
# named cases are optional - but ensure that translation does not add new ones
|
||||||
|
if not right_named.issubset(left_named):
|
||||||
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -48,17 +108,23 @@ def validate_po(locale: str, path: str) -> bool:
|
||||||
success = True
|
success = True
|
||||||
po = polib.pofile(path)
|
po = polib.pofile(path)
|
||||||
for entry in po:
|
for entry in po:
|
||||||
if entry.msgstr and not has_equal_placeholders(entry.msgid, entry.msgstr):
|
if entry.msgstr:
|
||||||
print("Number of variables mismatched in " + locale)
|
if not validate_placeholders(entry.msgstr):
|
||||||
print(entry.msgid + " -> " + entry.msgstr)
|
success = False
|
||||||
print()
|
if not has_equal_placeholders(entry.msgid, entry.msgstr):
|
||||||
success = False
|
|
||||||
for plural in entry.msgstr_plural.values():
|
|
||||||
if plural and not has_equal_placeholders(entry.msgid, plural):
|
|
||||||
print("Number of variables mismatched in " + locale)
|
print("Number of variables mismatched in " + locale)
|
||||||
print(entry.msgid + " -> " + plural)
|
print(entry.msgid + " -> " + entry.msgstr)
|
||||||
print()
|
print()
|
||||||
success = False
|
success = False
|
||||||
|
for plural in entry.msgstr_plural.values():
|
||||||
|
if plural:
|
||||||
|
if not validate_placeholders(plural):
|
||||||
|
success = False
|
||||||
|
if not has_equal_placeholders(entry.msgid, plural):
|
||||||
|
print("Number of variables mismatched in " + locale)
|
||||||
|
print(entry.msgid + " -> " + plural)
|
||||||
|
print()
|
||||||
|
success = False
|
||||||
return success
|
return success
|
||||||
|
|
||||||
success = True
|
success = True
|
||||||
|
|
Loading…
Reference in New Issue