mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
merge i18n into qt/
This commit is contained in:
parent
5876866565
commit
5ba0198a98
10 changed files with 218 additions and 1 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,4 +10,3 @@ build
|
||||||
pyenv
|
pyenv
|
||||||
.mypy_cache
|
.mypy_cache
|
||||||
__pycache__
|
__pycache__
|
||||||
i18n
|
|
||||||
|
|
1
qt/.gitignore
vendored
1
qt/.gitignore
vendored
|
@ -22,3 +22,4 @@ aqt_data/web/webview.js
|
||||||
dist
|
dist
|
||||||
aqt.egg-info
|
aqt.egg-info
|
||||||
build
|
build
|
||||||
|
i18n/anki.pot
|
||||||
|
|
1
qt/i18n/.gitignore
vendored
Normal file
1
qt/i18n/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.build
|
21
qt/i18n/Makefile
Normal file
21
qt/i18n/Makefile
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
SHELL := bash
|
||||||
|
.SHELLFLAGS := -eu -o pipefail -c
|
||||||
|
.DELETE_ON_ERROR:
|
||||||
|
MAKEFLAGS += --warn-undefined-variables
|
||||||
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
|
||||||
|
$(shell mkdir -p .build)
|
||||||
|
|
||||||
|
.PHONY: develop
|
||||||
|
develop: .build/develop
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
|
||||||
|
.build/develop: $(wildcard translations/anki.pot/*)
|
||||||
|
./build-mo-files
|
||||||
|
./copy-qt-files
|
||||||
|
@touch $@
|
17
qt/i18n/build-mo-files
Executable file
17
qt/i18n/build-mo-files
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# build mo files
|
||||||
|
#
|
||||||
|
|
||||||
|
targetDir="../anki-qt/aqt_data/locale"
|
||||||
|
mkdir -p $targetDir
|
||||||
|
|
||||||
|
echo "Compiling *.po..."
|
||||||
|
for file in translations/anki.pot/*
|
||||||
|
do
|
||||||
|
outdir=$(echo $file | \
|
||||||
|
perl -pe "s%translations/anki.pot/(.*)%$targetDir/\1/LC_MESSAGES%")
|
||||||
|
outfile="$outdir/anki.mo"
|
||||||
|
mkdir -p $outdir
|
||||||
|
msgfmt $file --output-file=$outfile
|
||||||
|
done
|
108
qt/i18n/check-po-files.py
Normal file
108
qt/i18n/check-po-files.py
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# locate any translations that have invalid format strings
|
||||||
|
#
|
||||||
|
|
||||||
|
import os, re, sys
|
||||||
|
po_dir = "translations/anki.pot"
|
||||||
|
|
||||||
|
msg_re = re.compile(r"^(msgid|msgid_plural|msgstr|)(\[[\d]\])? \"(.*)\"$")
|
||||||
|
cont_re = re.compile(r"^\"(.*)\"$")
|
||||||
|
pct_re = re.compile(r"%(?:\([^\)]+?\))?[#+\-\d.]*[a-zA-Z]")
|
||||||
|
path_re = re.compile(r"#: (.+)$")
|
||||||
|
|
||||||
|
def check_reps(path, t1, strs):
|
||||||
|
allZero = True
|
||||||
|
for s in strs:
|
||||||
|
if s:
|
||||||
|
allZero = False
|
||||||
|
if allZero:
|
||||||
|
return
|
||||||
|
|
||||||
|
orig = t1 or ""
|
||||||
|
for s in strs:
|
||||||
|
if not reps_match(orig, s):
|
||||||
|
return "{}\n{}\n{}\n".format(path, orig, strs)
|
||||||
|
|
||||||
|
def reps_match(t1, t2):
|
||||||
|
for char in "{}":
|
||||||
|
if t1.count(char) != t2.count(char):
|
||||||
|
return False
|
||||||
|
|
||||||
|
t1 = t1.replace("%%", "")
|
||||||
|
t2 = t2.replace("%%", "")
|
||||||
|
|
||||||
|
if t1.count("%"):
|
||||||
|
matches = set(pct_re.findall(t1))
|
||||||
|
matches2 = set(pct_re.findall(t2))
|
||||||
|
return matches == matches2
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def fix_po(path):
|
||||||
|
last_msgid = None
|
||||||
|
last_msgstr = None
|
||||||
|
last_path = None
|
||||||
|
lines = []
|
||||||
|
state = "outside"
|
||||||
|
problems = []
|
||||||
|
strs = []
|
||||||
|
|
||||||
|
for line in open(path):
|
||||||
|
lines.append(line)
|
||||||
|
|
||||||
|
# comment?
|
||||||
|
m = path_re.match(line)
|
||||||
|
if m:
|
||||||
|
last_path = m.group(1)
|
||||||
|
|
||||||
|
# starting new id/str?
|
||||||
|
m = msg_re.match(line)
|
||||||
|
if m:
|
||||||
|
label, num, text = m.group(1), m.group(2), m.group(3)
|
||||||
|
if label == "msgid":
|
||||||
|
last_msgid = text
|
||||||
|
state = "id"
|
||||||
|
strs = []
|
||||||
|
elif label == "msgid_plural":
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
state = "str"
|
||||||
|
strs.append(text)
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
# continuing previous id/str?
|
||||||
|
m = cont_re.match(line)
|
||||||
|
if m:
|
||||||
|
if state == "id":
|
||||||
|
last_msgid += m.group(1)
|
||||||
|
elif state == "str":
|
||||||
|
strs[-1] += m.group(1)
|
||||||
|
else:
|
||||||
|
assert 0
|
||||||
|
|
||||||
|
continue
|
||||||
|
|
||||||
|
state = "outside"
|
||||||
|
if last_msgid:
|
||||||
|
p = check_reps(last_path, last_msgid, strs)
|
||||||
|
if p:
|
||||||
|
problems.append(p)
|
||||||
|
# print("{0}\nProblems in {1}:\n{0}\n{2}".format("*"*60, path, "\n".join(problems)))
|
||||||
|
# return 1
|
||||||
|
last_msgid = None
|
||||||
|
|
||||||
|
if problems:
|
||||||
|
print("{0}\nProblems in {1}:\n{0}\n{2}".format("*"*60, path, "\n".join(problems)))
|
||||||
|
|
||||||
|
return len(problems)
|
||||||
|
|
||||||
|
problems = 0
|
||||||
|
for po in os.listdir(po_dir):
|
||||||
|
path = os.path.join(po_dir, po)
|
||||||
|
problems += fix_po(path)
|
||||||
|
|
||||||
|
if problems:
|
||||||
|
sys.exit(1)
|
9
qt/i18n/copy-qt-files
Executable file
9
qt/i18n/copy-qt-files
Executable file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
out=../anki-qt/aqt_data/locale
|
||||||
|
mkdir -p $out
|
||||||
|
|
||||||
|
qtTranslations=$(python -c "from PyQt5.QtCore import *; print(QLibraryInfo.location(QLibraryInfo.TranslationsPath))")
|
||||||
|
rsync -av $qtTranslations/qt* $out
|
16
qt/i18n/update-crowdin
Executable file
16
qt/i18n/update-crowdin
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
proj=anki
|
||||||
|
|
||||||
|
if [ "$key" = "" ]; then
|
||||||
|
echo "key not defined"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
./update-pot
|
||||||
|
|
||||||
|
curl \
|
||||||
|
-F "files[/anki.pot]=@anki.pot" \
|
||||||
|
https://api.crowdin.com/api/project/$proj/update-file?key=$key
|
29
qt/i18n/update-from-crowdin
Executable file
29
qt/i18n/update-from-crowdin
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
proj=anki
|
||||||
|
|
||||||
|
if [ "$key" = "" ]; then
|
||||||
|
echo "key not defined"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# fetch translations from crowdin
|
||||||
|
if [ ! -f all.zip ]; then
|
||||||
|
curl https://api.crowdin.com/api/project/$proj/export?key=$key
|
||||||
|
curl -o all.zip https://api.crowdin.com/api/project/$proj/download/all.zip?key=$key
|
||||||
|
fi
|
||||||
|
|
||||||
|
# unzip
|
||||||
|
unzip -o all.zip
|
||||||
|
|
||||||
|
# make sure translations are valid
|
||||||
|
python check-po-files.py
|
||||||
|
|
||||||
|
rm all.zip
|
||||||
|
|
||||||
|
# send translations to github
|
||||||
|
git add translations
|
||||||
|
git commit -m update || true
|
||||||
|
git push
|
16
qt/i18n/update-pot
Executable file
16
qt/i18n/update-pot
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# update translation files
|
||||||
|
#
|
||||||
|
|
||||||
|
all=all.files
|
||||||
|
echo "Updating anki.pot..."
|
||||||
|
for i in ../anki-lib-python/anki/{*.py,importing/*.py,template/*.py}; do
|
||||||
|
echo $i >> $all
|
||||||
|
done
|
||||||
|
for i in ../anki-qt/aqt/{*.py,forms/*.py}; do
|
||||||
|
echo $i >> $all
|
||||||
|
done
|
||||||
|
|
||||||
|
xgettext -cT: -s --no-wrap --files-from=$all --output=anki.pot
|
||||||
|
rm $all
|
Loading…
Reference in a new issue