Last active
August 17, 2020 11:40
-
-
Save yelizariev/5cc80c634cce9271132fb141971fe23a to your computer and use it in GitHub Desktop.
Automatic translation of odoo files by using existing translation (e.g. from Ukrainian to Russian, English to Russian, Russian to Russian)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# install dependencies | |
sudo pip install polib | |
sudo pip install google-cloud-translate==2.0.0 | |
# https://docs.transifex.com/client/installing-the-client | |
sudo pip install transifex-client | |
# prepare and export your google cloud credentials | |
# See https://cloud.google.com/translate/docs/basic/setup-basic | |
# and https://cloud.google.com/docs/authentication/getting-started | |
export GOOGLE_APPLICATION_CREDENTIALS=path/to/credentials.json | |
# prepare and export transifex token | |
# https://www.transifex.com/user/settings/api/ | |
export TX_TOKEN=<your_Transifex_API_token> | |
cd | |
wget https://gist.github.com/yelizariev/5cc80c634cce9271132fb141971fe23a/raw/translate.py | |
wget https://gist.github.com/yelizariev/5cc80c634cce9271132fb141971fe23a/raw/fix-translation.py | |
wget https://gist.github.com/yelizariev/5cc80c634cce9271132fb141971fe23a/raw/move-translation.py | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import re | |
import polib | |
TAGS = ['menuselection', 'doc', 'ref', 'class', 'meth', 'func'] | |
def fix_po_item(msgid, msgstr): | |
res = msgstr | |
for t in TAGS: | |
search = re.search(r"(:%s:`[^`]*`)" % t, msgid) | |
if not search: | |
# no tag in source | |
continue | |
original_value = search.group(1) | |
res = re.sub(":\s*%s\s*:\s*`[^`]*`" % t, ' %s' % original_value, res) | |
print ("tag :%s: is replaced with following:\n%s" % (t, original_value)) | |
# fix replaced quotes | |
res = re.sub(""", "`", res) | |
res = re.sub("'", "'", res) | |
# fix variables | |
res = re.sub("% \(", "%(", res) | |
# TODO: this doesn't work well in latin aplhabet | |
res = re.sub("\) s", ")s ", res) | |
res = re.sub("% \.", "%.", res) | |
res = re.sub("% S", "%s", res) | |
res = re.sub("% s", "%s", res) | |
res = re.sub("% D", " %d", res) | |
res = re.sub("% d", " %d", res) | |
res = re.sub("% R", " %r", res) | |
res = re.sub("% r", " %r", res) | |
res = re.sub("%set", "% set", res) | |
res = re.sub("%S", "%s ", res) | |
res = re.sub("\$ {", "${", res) | |
#res = re.sub("# ", "#", res) | |
# fix broken links | |
res = re.sub("\> `_", ">`_", res) | |
if res != msgstr: | |
return res | |
def fix_po(fname): | |
dest_po = polib.pofile(fname) | |
changed = False | |
for dest_entry in dest_po: | |
res = fix_po_item(dest_entry.msgid, dest_entry.msgstr) | |
# python3 check | |
if isinstance(res, str): | |
changed = True | |
dest_entry.msgstr = res | |
if changed: | |
dest_po.save() | |
if __name__ == '__main__': | |
print (sys.argv) | |
fname = sys.argv[1] | |
fix_po(fname) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import polib | |
import os | |
def move_po(lang, source_path, dest_fname): | |
src_fname = os.path.join(source_path, dest_fname) | |
if not os.path.exists(src_fname): | |
print ("Source file doesn't exist: %s" % src_fname) | |
return | |
src_po = polib.pofile(src_fname) | |
dest_po = polib.pofile(dest_fname) | |
changed = False | |
for dest_entry in dest_po: | |
src_entry = src_po.find(dest_entry.msgid) | |
if not src_entry: | |
# print ("%s: source entry not found or empty: \n%s\n" % (src_fname, dest_entry.msgid)) | |
continue | |
if dest_entry.msgstr == src_entry.msgstr: | |
# same translation | |
continue | |
if not any(s in dest_entry.msgstr for s in {'&', '%', '$'}): | |
# we update only entries with special characters See https://github.com/odoo/odoo/issues/43161#issuecomment-575015099 | |
continue | |
#print (u'========================================\nUpdate \n%s\n--->\n%s ' % (str(dest_entry.msgstr), str(src_entry.msgstr))) | |
dest_entry.msgstr = src_entry.msgstr | |
changed = True | |
if changed: | |
dest_po.save() | |
if __name__ == '__main__': | |
print (sys.argv) | |
lang = sys.argv[1] | |
source_path = sys.argv[2] | |
dest_fname = sys.argv[3] | |
move_po(lang, source_path, dest_fname) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Transifex usually syncs translation by itself: https://docs.transifex.com/translation-memory/tm-introduction | |
# You may need this script only to fix previously translated terms | |
# You need to use this script twice: for CE and EE | |
# Each time you need two odoo folders: source and target | |
LANG=ru | |
VERSION_SOURCE=odoo-12 | |
VERSION_TARGET=odoo-13 | |
# download existing translations | |
cd path/to/odoo-source | |
tx pull -r "$VERSION_SOURCE.*" -l $LANG -f | |
cd path/to/odoo-target | |
tx pull -r "$VERSION_TARGET.*" -l $LANG -f | |
# make a commit to easily compare changes | |
git commit -a -m "sync translations with transifex" | |
# move translations | |
#export PYTHONIOENCODING=utf-8 | |
find . -iname "ru.po" | xargs -L1 python3 ~/move-translation.py $LANG ../path/to/odoo-source | |
# upload translation | |
tx push -r "$VERSION_TARGET.*" -l ru -t |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import polib | |
from google.cloud import translate_v2 as translate | |
translate_client = translate.Client() | |
def translate_po(lang, fname): | |
po = polib.pofile(fname) | |
for entry in po: | |
if entry.msgstr: | |
# already translated | |
continue | |
try: | |
tr_text = translate_text(entry.msgid, 'en', lang) | |
except Exception as e: | |
# save file and exit | |
print ('ERROR on translation: ', e) | |
break | |
entry.msgstr = tr_text | |
po.save() | |
def translate_text(text, src, dest): | |
result = translate_client.translate(text, source_language=src, target_language=dest) | |
return result['translatedText'] | |
if __name__ == '__main__': | |
print (sys.argv) | |
lang = sys.argv[1] | |
fname = sys.argv[2] | |
translate_po(lang, fname) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
VERSION=odoo-13-doc | |
SRC_LANG=uk | |
DEST_LANG=ru | |
git clone https://github.com/odoo/documentation-user.git | |
cd documentation-user | |
tx pull -r "$VERSION.*" -l $SRC_LANG -f | |
tx pull -r "$VERSION.*" -l $DEST_LANG -f | |
# translate | |
find . -type d -iname i18n | xargs -L1 python3 ~/translate.py $SRC_LANG $DEST_LANG | |
# fix | |
find locale/$DEST_LANG/LC_MESSAGES -iname "*.po" | xargs -L1 python3 ~/fix-translation.py | |
# upload | |
tx push -r "$VERSION.*" -l $DEST_LANG -t |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# You need to use this script twice: for CE and EE | |
cd path/to/odoo | |
SRC_LANG=uk | |
DEST_LANG=ru | |
VERSION=odoo-12 | |
# download source | |
tx pull -r "$VERSION.*" -l $SRC_LANG -f | |
tx pull -r "$VERSION.*" -l $DEST_LANG -f | |
# translate | |
find . -type d -iname i18n | xargs -L1 python3 ~/translate.py uk ru | |
# fix | |
find . -iname "ru.po" | xargs -L1 python3 ~/fix-translation.py | |
# upload translation | |
tx push -r "$VERSION.*" -l ru -t |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
RESOURSES=(website_event_stand saas_trial release_notes openerp_website openerp_enterprise main help features) | |
SRC_LANG=uk | |
DEST_LANG=ru | |
# TODO: use command "tx" instead | |
# get it from transifex.com | |
COOKIE="Cookie: ......" | |
mkdir /tmp/odoo.com/ | |
cd /tmp/odoo.com/ | |
# download | |
for r in ${RESOURSES[@]}; do | |
mkdir -p $r/i18n/ | |
wget https://www.transifex.com/odoo/odoo-com/$r/$SRC_LANG/download/for_use/ --header="$COOKIE" -O $r/i18n/$SRC_LANG.po | |
wget https://www.transifex.com/odoo/odoo-com/$r/$DEST_LANG/download/for_translation/ --header="$COOKIE" -O $r/i18n/$DEST_LANG.po | |
done | |
# translate | |
find . -type d -iname i18n | xargs -L1 python3 ~/translate.py uk ru |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import os | |
import subprocess | |
import polib | |
from google.cloud import translate_v2 as translate | |
translate_client = translate.Client() | |
def translate_po(src_lang, dest_lang, src_fname, dest_fname, template_fname): | |
if not os.path.exists(src_fname): | |
print ("Source file doesn't exist: %s" % src_fname) | |
return | |
if not os.path.exists(dest_fname): | |
print ("Target file doesn't exist: %s" % dest_fname) | |
subprocess.check_output(["cp %s" % template_fname, dest_fname]) | |
src_po = polib.pofile(src_fname) | |
dest_po = polib.pofile(dest_fname) | |
for dest_entry in dest_po: | |
if dest_entry.msgstr: | |
# already translated | |
continue | |
if any(s in dest_entry.msgid for s in ["%", "<", ">", "$", "&", "#"]): | |
# don't translate messages with special symbols | |
continue | |
src_entry = src_po.find(dest_entry.msgid) | |
if not src_entry: | |
print ("%s: source entry not found or empty: \n%s\n" % (src_fname, dest_entry.msgid)) | |
continue | |
if src_entry.msgstr == src_entry.msgid: | |
# Not for translattion. | |
# Just copy original. | |
# If we leave it empty, transifex will always offer to translate it, which is annoying | |
dest_entry.msgstr = src_entry.msgid | |
continue | |
try: | |
tr_text = translate_text(src_entry.msgstr, src_lang, dest_lang) | |
except Exception as e: | |
# save file and exit | |
print ('ERROR on translation: ', e) | |
break | |
dest_entry.msgstr = tr_text | |
dest_po.save() | |
def translate_text(text, src, dest): | |
result = translate_client.translate(text, source_language=src, target_language=dest) | |
return result['translatedText'] | |
if __name__ == '__main__': | |
print (sys.argv) | |
src_lang = sys.argv[1] | |
dest_lang = sys.argv[2] | |
if len(sys.argv) == 4: | |
folder = sys.argv[3] | |
src_fname = os.path.join(folder, '%s.po' % src_lang) | |
dest_fname = os.path.join(folder, '%s.po' % dest_lang) | |
template_fname = os.path.join(folder, '*.pot') | |
else: | |
src_fname = sys.argv[3] | |
dest_fname = sys.argv[4] | |
template_fname = sys.argv[5] | |
translate_po(src_lang, dest_lang, src_fname, dest_fname, template_fname) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment