Hi, 
This is my first time posting on this forum, so please be gentle with me. 
Currently I'm working as a translator for Blender project, translating 
reference manual to Vietnamese. I have completed the UI and done some 
chapters on the translation set, which can be used as a database for 
untranslated text. I'm only interested to output to PO file. My current 
solution is to

1. Write an extension, and making use of  'app.connect('doctree-resolved', 
doctree_resolved)'.
2. Within 'doctree_resolved', I use a for loop with 
extract_messages(doctree) to traverse and extract all messages to be 
translated.
3. I use 'node.walk' with a 'visitor' (extends nodes.TreeCopyVisitor) to 
traverse all children nodes of the current node.
4. In the visitor, I use the 'default_visit' to traverse the children 
(recursively) to the end instance of nodes.Text where I use 'astext()' to 
extract the English text, then use a lookup routine to find appropriate 
'translation' for the text.
5. Due to the fact that some texts are REQUIRED to have the original 
English appending to it (ending), a methodology tor leave crumbs for 
Vietnamese readers, who would like to reference back to English original 
HTML texts. These items are often from 'inline', 'title', 'rubric' etc.. so 
I use a flag to identify when translation texts (if exists) will include 
the original in it (and called this combination as translation text).
6. I use Message and Catalog to store English (msgid) and translation 
(msgstr) and write them out to a separate directory before merging them 
with existing translations by diff.

My questions:

1. How should I store translation text? Currently I'm forced to insert a 
variable in the 'docutils.Node' to store the translation (for testing).
2. How can I use the same 'extract_messages(doctree)' mechanism to extract 
English and Translation at the same time? Currently everything is tied to 
the overloaded  'astext()' method and that seemed to go to __repr__(self), 
how would I approach to solve this problem?

Best regards,
Hoang Tran

All the code is attached.

-- 
You received this message because you are subscribed to the Google Groups 
"sphinx-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sphinx-users/7e65b85e-c7dd-4104-8cec-3732c1de9b69%40googlegroups.com.
import os
import io
import re
import json
from common import Common as cm
from pobase import POBasic
import docutils
from docutils import nodes
from sphinx import addnodes, roles
from pprint import pprint as PP
from six import text_type
from sphinx.util.nodes import extract_messages, traverse_translatable_index
from distutils import log as logger
from sphinx.locale import _, __
from sphinx_intl import catalog as c
from babel.messages import pofile
from babel.messages.catalog import Message, Catalog
from pprint import pprint as pp
from googletrans import Translator as GTR

#from Levenshtein import distance as DS
from markupsafe import Markup
try:
    import html
except ImportError:
    html = None

unescape = getattr(html, 'unescape', None)
if unescape is None:
    # HTMLParser.unescape is deprecated since Python 3.4, and will be removed
    # from 3.9.
    unescape = html_parser.HTMLParser().unescape


# sudo apt install python-pip python3-pip
# pip3 install googletrans
from googletrans import Translator

use_google_translate = False

# type: <class 'docutils.nodes.caption'>
# type: <class 'docutils.nodes.emphasis'>
# type: <class 'docutils.nodes.field_name'>
# type: <class 'docutils.nodes.image'>
# type: <class 'docutils.nodes.inline'>
# type: <class 'docutils.nodes.line'>
# type: <class 'docutils.nodes.literal'>
# type: <class 'docutils.nodes.math'>
# type: <class 'docutils.nodes.math_block'>
# type: <class 'docutils.nodes.paragraph'>
# type: <class 'docutils.nodes.reference'>
# type: <class 'docutils.nodes.rubric'>
# type: <class 'docutils.nodes.strong'>
# type: <class 'docutils.nodes.superscript'>
# type: <class 'docutils.nodes.term'>
# type: <class 'docutils.nodes.Text'>
# type: <class 'docutils.nodes.title'>

def isIgnored(msg):
    is_ignore_word = cm.isIgnoredWord(msg)
    is_dos_command = cm.isDosCommand(msg)
    is_ignore_start = cm.isIgnoredIfStartsWith(msg)
    is_ignore_path = cm.isFilePath(msg)

    is_ignore = (is_ignore_word or is_dos_command or is_ignore_start or is_ignore_path)
    #is_ignore = (is_ignore_word or is_dos_command or is_ignore_start)
    if is_ignore:
        # print("checking for ignore")
        dict_ignore = {"is_ignore_word": is_ignore_word,
                       "is_dos_command": is_dos_command,
                       "is_ignore_start": is_ignore_start,
                       "is_ignore_path": is_ignore_path
                       }
        # pp(dict_ignore)
        for k, v in dict_ignore.items():
            if isinstance(v, bool) and (v == True):
                print(k, v, msg)
    return is_ignore


class TranslationFinder:
    def __init__(self):
        self.dic_path = "/home/htran/blender_documentations/new_po/vi.po"
        self.current_po_dir = "/home/htran/blender_documentations/blender_docs/locale/vi/LC_MESSAGES"
        self.json_dic_file = "/home/htran/Documents/menuselection_new_dictionary_sorted_translated_0028.json"

        self.json_dic_list = self.loadJSONDic()
        self.json_dic_list_lower = self.makeJSONLowerCaseDic(self.json_dic_list)
        self.dic_cat = c.load_po(self.dic_path)
        self.dic_cat_lower = self.poCatDictLower(self.dic_cat)
        self.translated_po_dic = None
        self.translated_po_dic_lower = None
        self.translated_po_dic, self.translated_po_dic_lower = self.loadTranslatedPO()
        self.tr = Translator()

        #po_dic = self.poCatToList(dic_cat)

        #po_dic_lower = self.poCatToListLower(dic_cat)
        #sorted_po_dic = sorted(po_dic)
        #PP(po_dic_lower)
        #sorted_lower_po_dic = sorted(po_dic_lower)

    def removeJSONDicNoTranslation(self, dic):
        dic_removable=[]
        for k,v in dic.items():
            has_translation = (len(v)>0)
            if not has_translation:
                dic_removable.append(k)

        new_dic = dic
        for k in dic_removable:
            new_dic.pop(k)
        return new_dic

    def makeJSONLowerCaseDic(self, dic):
        lcase_dic={}
        for k,v in dic.items():
            lk = k.lower()
            lv = v
            lcase_dic.update({lk:lv})
        #PP(lcase_dic)
        #exit(0)
        return lcase_dic

    def loadJSONDic(self, file_name=None):
        dic = None
        try:
            file_path = (self.json_dic_file if (file_name == None) else file_name)
            with open(file_path) as in_file:
                dic = json.load(in_file)
                if dic:
                    print("Loaded:{}".format(len(dic)))
                else:
                    raise Exception("dic [{}] is EMPTY. Not expected!", file_path)
        except Exception as e:
            print("Exception readDictionary Length of read dictionary:")
            print(e)
            raise e

        dic = self.removeJSONDicNoTranslation(dic)
        print("after cleaned:{}".format(len(dic)))
        return dic


    def POContentToDic(self, po_cat, dict, dict_lowercase):
        for m in po_cat:
            k = m.id
            v = m.string
            # is_debug = ("POV" in k)
            # if is_debug:
            #     print("{} => {}".format(k, v))
            #     exit(0)

            has_trans = v and (len(v) > 0)
            if (has_trans):
                is_same = (k == v)
                if (is_same):
                    continue
                else:
                    dict.update({k:m})
                    dict_lowercase.update({k.lower():m})


    def loadTranslatedPO(self):
        all_po_dict={}
        all_po_dict_lower = {}
        getter = POBasic(self.current_po_dir, False)
        po_dir_list = getter.getSortedPOFileList()
        for(index, po_file_path) in enumerate(po_dir_list):
            if (len(po_file_path) <= 0):
                continue
            po_cat = c.load_po(po_file_path)
            self.POContentToDic(po_cat, all_po_dict, all_po_dict_lower)

        # print("all_po_dict:")
        # pp(all_po_dict)
        # exit(0)
        return all_po_dict, all_po_dict_lower

    def poCatToList(self, po_cat):
        l = []
        for index, m in enumerate(po_cat):
            k = m.id
            v = m
            l.append((k, v))
        return l

    def poCatToListLower(self, po_cat):
        l = []
        for index, m in enumerate(po_cat):
            k = m.id.lower()
            v = m
            l.append((k, v))
        return l

    def poCatDictLower(self, po_cat):
        l = {}
        for index, m in enumerate(po_cat):
            k = m.id.lower()
            v = m
            l.update({k: v})
        return l

    # PP(sorted_lower_po_dic)

    def dump_po(self, filename, catalog):
        dirname = os.path.dirname(filename)
        if not os.path.exists(dirname):
            os.makedirs(dirname)

        # Because babel automatically encode strings, file should be open as binary mode.
        with io.open(filename, 'wb') as f:
            pofile.write_po(f, catalog, width=4096)


    def removeOriginal(self, msg, trans):
        # print("removeOriginal msg = [{}], trans = [{}]".format(msg, trans))
        orig_index = -1
        # if trans:
        #     orig_index = trans.find(trans, "-- ")
        #     has_orig = (msg in trans) and (orig_index > 0)
        #     is_empty_trans = (orig_index == 0)
        #     if is_empty_trans:
        #         return None
        #
        #     if has_orig:
        #         word_list = trans.split("-- ")
        #         trans = word_list[0]
        #         return trans
        # return None

        msg = re.escape(msg)
        p = r'\b{}\b'.format(msg)
        has_original = (re.search(p, trans, flags=re.I) != None)
        endings=("", "s", "es", "ies", "ed", "ing", "lly",)
        if has_original:
            for end in endings:
                p = r'-- {}{}'.format(msg, end)
                trans = re.sub(p, "", trans, flags=re.I)

            for end in endings:
                p = r'{}{} --'.format(msg, end)
                trans = re.sub(p, "", trans, flags=re.I)

            for end in endings:
                p = r'\\b{}{}\\b'.format(msg, end)
                trans = re.sub(p, "", trans, flags=re.I)
            trans = trans.strip()
            is_empty = (len(trans) == 0)
            if is_empty:
                trans = None

            # if trans:
            #     print("removeOriginal msg: [{}] => trans: [{}]".format(msg, trans))
            # else:
            #     print("removeOriginal REMOVED AND EMPTY")
        # else:
        #     print("removeOriginal DO NOT HAVE ORIGINAL in translation")

        return trans

    def isInList(self, msg, find_list, is_lower=False):
        orig_msg = str(msg)
        trans = None
        if is_lower:
            msg = msg.lower()
        if msg in find_list:
            trans = find_list[msg]
        else:
            trams = None

        if isinstance(trans, Message):
            trans = trans.string
        else:
            trans = trans

        # is_debug = ("POV" in msg)
        # if is_debug:
        #     print("DEBUG: msg [{}] => [{}]".format(msg, trans))

        has_translation = trans and (len(trans) > 0) and (trans != 'None')
        if has_translation:
            trans = trans.strip()
            trans = self.removeOriginal(msg, trans)
            trans = cm.matchCase(orig_msg, trans)
        else:
            trans = None
        return  trans

    def findTranslationByFragment(self, msg):
        #print("findTranslationByFragment", msg)
        if isIgnored(msg):
            return None

        #print("findTranslationByFragment:[{}]".format(msg))
        msg = unescape(msg)

        trans_list = []
        trans = str(msg)
        for w_start, w_end, w_match_0, w_match_1 in cm.patternMatchAsList(cm.WORD_ONLY_FIND, msg):

            if isIgnored(w_match_0):
                continue

            trans_word = trans_finder.findTranslation(w_match_0)
            trans_word_entry = (w_start, w_end, w_match_0, trans_word)

            # print("FIND TRANS: w_start, w_end, w_match_0, w_match_1, trans_word")
            # print(w_start, w_end, w_match_0, w_match_1, trans_word)

            trans_list.append(trans_word_entry)

        # print("findTranslationByFragment trans_list")
        # pp(trans_list)

        for w_start, w_end, w_match_0, trans_word in reversed(trans_list):
            # print("REPLACING: w_start, w_end, w_match_0, trans_word")
            # print(w_start, w_end, w_match_0, trans_word)
            if trans_word:
                w_end = w_start + len(w_match_0)
                st = trans[:w_start]
                se = trans[w_end:]
                trans = st + trans_word + se
            #     print("findTranslationByFragment st:[{}], se:[{}], trans:[{}]".format(st, se, trans))
            #     #trans = trans.strip()
            # print("findTranslationByFragment trans:[{}]".format(trans))

        is_changed = (trans != msg)
        if not is_changed:
            trans = None

        # if trans:
        #     print("RESULT findTranslationByFragment: [{}] => [{}]".format(msg, trans))

        return trans

    def findTranslation(self, msg):
        list_name = "self.dic_cat"
        trans = self.isInList(msg, self.dic_cat)
        if not trans:
            list_name = "self.dic_cat_lower"
            trans = self.isInList(msg, self.dic_cat_lower, is_lower=True)
            if not trans:
                list_name = "self.translated_po_dic"
                trans = self.isInList(msg, self.translated_po_dic)
                if not trans:
                    list_name = "self.translated_po_dic_lower"
                    trans = self.isInList(msg, self.translated_po_dic_lower, is_lower=True)
                    if not trans:
                        list_name = "self.json_dic_list"
                        trans = self.isInList(msg, self.json_dic_list)
                        if not trans:
                            list_name = "self.json_dic_list_lower"
                            trans = self.isInList(msg, self.json_dic_list_lower, is_lower=True)
                            if not trans:
                                list_name = ""
                                return None

        has_translation = trans and (len(trans) > 0) and (trans != 'None')
        if has_translation:
            trans = trans.strip()
            trans = self.removeOriginal(msg, trans)
            print("findTranslation in {} [{}] => [{}]".format(list_name, msg, trans))
        else:
            trans = None
        return trans


trans_finder = TranslationFinder()

MNU_SEL = 'menuselection'
MNU_SEP = '-->'
CLASS = 'classes'
RAWTXT = 'rawtext'
DOC = 'doc' #:doc:`keyframe
STD_REF="std std-ref" #:ref:`easings
X_REF="xref std std-term" #:term:`walk cycle
BACKQUOTE="`"
TR_ED='translated'
def print_separator(output_path):
    print("docname:", output_path)
    print("-" * 30)

def print_result_list(result):
    PP(result)

# type: <class 'docutils.nodes.caption'>
# type: <class 'docutils.nodes.emphasis'>
# type: <class 'docutils.nodes.field_name'>
# type: <class 'docutils.nodes.image'>
# type: <class 'docutils.nodes.inline'>
# type: <class 'docutils.nodes.line'>
# type: <class 'docutils.nodes.literal'>
# type: <class 'docutils.nodes.math'>
# type: <class 'docutils.nodes.math_block'>
# type: <class 'docutils.nodes.paragraph'>
# type: <class 'docutils.nodes.reference'>
# type: <class 'docutils.nodes.rubric'>
# type: <class 'docutils.nodes.strong'>
# type: <class 'docutils.nodes.superscript'>
# type: <class 'docutils.nodes.term'>
# type: <class 'docutils.nodes.Text'>
# type: <class 'docutils.nodes.title'>

class TranslationNodeVisitor(nodes.TreeCopyVisitor):
    """Raise `nodes.NodeFound` if non-simple list item is encountered.

    Here 'simple' means a list item containing only a paragraph with a
    single reference in it.
    """
    def setVars(self, node, msg, trans):
        self.current_node = node
        self.current_msg = msg
        if trans:
            self.current_trans = trans
        else:
            self.current_trans = msg
        self.fuzzy_list = []
        self.is_fuzzy = False
        self.is_title_node = False
        self.tr = None
        self.ref_trans=[]
        self.keep_original = False

    def trans_keyboard(self, msg):
        trans = None
        is_keyboard = (":kbd:" in msg)
        if not is_keyboard:
            return None

        if isIgnored(msg):
            return None

        orig_text = str(msg)
        for w_start, w_end, w_match_0, w_match_1 in cm.patternMatchAsList(cm.TEXT_BETWEEN_REFS, msg):

            if w_match_1:
                trans = cm.translateKeyboardDef(w_match_1)
                if trans:
                    orig_text = re.sub(w_match_1, trans, orig_text)
        return orig_text

    def setNodeTranslated(self, node):
        node[TR_ED] = True
        print("NODE TRANSLATED!!!")

    def getNodeTranslated(self, node):
        try:
            transed = node[TR_ED]
            print("NODE TRANSLATION:{}".format(transed))
            return transed
        except Exception as e:
            return False

    def connectMenuItems(self, list_of_menu_items):
        trans_list = []
        for item in list_of_menu_items:
            item = item.strip()
            print("item:", item)
            trans = trans_finder.findTranslation(item)
            if (trans):
                trans = "{} ({})".format(trans, item)
            else:
                trans = "({})".format(item)
            print("trans:", trans)
            trans_list.append(trans)
        return trans_list

    # /home/htran/blender_documentations/blender_docs/build/rstdoc/addons/3d_view/3d_navigation.html
    def trans_menuselection(self, msg):
        print("trans_menuselection", msg)
        is_menu = (":menuselection:" in msg)
        if not is_menu:
            return None

        if isIgnored(msg):
            return None

        trans = None
        for w_start, w_end, w_match_0, w_match_1 in cm.patternMatchAsList(cm.TEXT_BETWEEN_REFS, msg):
            print("w_start, w_end, w_match_0, w_match_1")
            print(w_start, w_end, w_match_0, w_match_1)

            if isIgnored(w_match_1):
                continue

            if w_match_1:
                list_of_menu_items = w_match_1.split(MNU_SEP)
                trans_list = self.connectMenuItems(list_of_menu_items)
                trans = " {} ".format(MNU_SEP).join(trans_list)
                trans = msg[:w_start+1] + trans + msg[w_end-1:]
                print("FINAL {}".format(trans))
                break
        return trans

    def trans_ref(self, msg):
        print("trans_ref", msg)
        is_ref = (cm.REF_KEYS.search(msg) != None)
        if not is_ref:
            return None

        if isIgnored(msg):
            return None

        trans = None
        for w_start, w_end, w_match_0, w_match_1 in cm.patternMatchAsList(cm.TEXT_BETWEEN_REFS, msg):
            print("w_start, w_end, w_match_0, w_match_1")
            print(w_start, w_end, w_match_0, w_match_1)

            if isIgnored(w_match_1):
                continue

            trans = trans_finder.findTranslation(w_match_1)
            if trans:
                trans = "{} -- {}".format(trans, w_match_1)
                trans = msg[:w_start+1] + trans + msg[w_end-1:]

        return trans

    def printNode(self, node, extra=None):
        print('-'*50)
        if extra:
            print(extra)

        # print("self.current_msg:[{}]".format(self.current_msg))
        print("type:", type(node))
        if hasattr(node, 'children'):
            print("children:", node.children)

        #print("name:", type(node.name))
        print("pp node:")
        pp(node)
        if hasattr(node, 'astext'):
            msg = node.astext()
            msg = msg.strip()
            print("node text: [{}]".format(msg))

        if hasattr(node, 'rawsource'):
            print("rawsource: [{}]".format(node.rawsource))

        if hasattr(node, 'line'):
            print("line", node.line)

        print("")
        # print("dir:", dir(node))
        # print("len:", len(node))


    def translate_text(self, msg, include_origin_in_translation=False, bracketting_origin=False):

        if isIgnored(msg):
            return None

        trans = trans_finder.findTranslation(msg)
        is_repeat = (trans == msg)
        valid_trans = (trans and not is_repeat)
        if valid_trans:
            print('has translation:', trans)
        else:
            trans = self.trans_keyboard(msg)
            if not trans:
                trans = self.trans_menuselection(msg)
                if not trans:
                    trans = self.trans_ref(msg)
                    if not trans:
                        trans = trans_finder.findTranslationByFragment(msg)
                        if not trans:
                            trans = None

        if trans:
            if include_origin_in_translation:
                if bracketting_origin:
                    trans = "{} ({})".format(trans, msg)
                else:
                    trans = "{} -- {}".format(trans, msg)
        else:
            if include_origin_in_translation:
                if bracketting_origin:
                    trans = "-- ({})".format(msg)
                else:
                    trans = "-- {}".format(msg)

        print("trans: [{}]".format(trans))
        print('-'*30)
        return trans

    def translate(self, node, include_origin_in_translation=False, bracketting_origin=False):
        print("translate node:")
        msg = node.astext()
        trans = self.translate_text(msg, include_origin_in_translation = include_origin_in_translation, bracketting_origin = bracketting_origin)
        return trans


    def default_visit(self, node):
        print("-"*50)
        # class 'docutils.nodes.emphasis' ##>
        # class 'docutils.nodes.inline' ##>
        # class 'docutils.nodes.literal' ##>
        # class 'docutils.nodes.reference' ##>
        # class 'docutils.nodes.strong' ##>

        print(type(node))
        is_inline = isinstance(node, nodes.inline)
        is_emphasis = isinstance(node, nodes.emphasis)
        is_title = isinstance(node, nodes.title)
        is_term = isinstance(node, nodes.term)
        is_rubric = isinstance(node, nodes.rubric)
        is_field_name = isinstance(node, nodes.field_name)
        is_reference = isinstance(node, nodes.reference)
        is_strong = isinstance(node, nodes.strong)

        if (is_emphasis or is_title or is_term or is_rubric or is_field_name or is_reference or is_strong or is_inline):
            l = {   "is_emphasis":is_emphasis,
                    "is_title":is_title,
                    "is_term":is_term,
                    "is_rubric":is_rubric,
                    "is_field_name":is_field_name,
                    "is_reference":is_reference,
                    "is_strong":is_strong,
                    "is_inline":is_inline }

            for k, v in l.items():
                if v:
                    msg = node.astext()
                    print(msg, "=>" ,k)

            print("TURN ON KEEP ORIGINAL")
            self.keep_original = True

        if isinstance(node, nodes.Text):
            #self.printNode(node, extra="default_visit, TEXT")
            msg = node.astext()
            trans = self.translate_text(msg)
            #this needs to be inserted manually in the file docutils.nodes, class Text

            if trans:
                if self.keep_original:
                    trans = "{} -- {}".format(trans, msg)
                print("MSG:", msg, "=> TRANSLATION:", trans)
            else:
                if self.keep_original:
                    trans = "-- {}".format(msg)
                print("NO TRANSLATION:", "MSG:", msg, "TRANS", trans)
            node.translation = trans
            if self.keep_original:
                print("TURN OFF KEEP ORIGINAL")
                self.keep_original = False
        else:
            has_children = hasattr(node, 'children')
            if has_children:
                for child in node.children:
                    self.default_visit(child)
            else:
                self.printNode(node, extra="default_visit, NOTHING")
            print("-" * 80)
            #raise nodes.SkipNode

            # class 'docutils.nodes.emphasis' ##>
            # class 'docutils.nodes.image'>
            # class 'docutils.nodes.inline' ##>
            # class 'docutils.nodes.literal' ##>
            # class 'docutils.nodes.math'>
            # class 'docutils.nodes.reference' ##>
            # class 'docutils.nodes.strong' ##>
            # class 'docutils.nodes.Text'>

            #elif isinstance(nodes.)
        # type: (nodes.Node) -> None

        # this is where no visit has been implemented????
        #pass

    def visit_emphasis(self, node):
        print("visit_emphasis")

    def visit_strong(self, node):
        print("visit_strong")

    def visit_emphasis(self, node):
        print("visit_emphasis")

    def visit_strong(self, node):
        print("visit_strong")
        #self.printNode(node)

    # def visit_bullet_list(self, node):
    #     # type: (nodes.Node) -> None
    #     pass
    def visit_emphasis(self, node):
        print("visit_emphasis")

    def visit_reference(self, node):
        print("visit_reference")

    def visit_inline(self, node):
        print("visit_inline")
        # for index, n in enumerate(node):
        #     self.printNode(n)
        #     is_xref = ('xref' in node['classes'])
        #     is_term = ('term' in node['classes'])
        #     is_menu = ('menuselection' in node['classes'])
        #     is_keyboard = ('kbd' in node['classes'])
        #     is_doc = ('doc' in node['classes'])
        #
        #     if is_xref:
        #         print("EXREF")
        #     elif is_term:
        #         print("TERM")
        #     elif is_menu:
        #         print("MENU")
        #     elif is_keyboard:
        #         print("KEYBOARD")
        #     elif is_doc:
        #         print("DOC")
        #
        #     has_rawtext = False
        #     raw_text = None
        #     has_uri = False
        #     uri = None
        #     try:
        #         raw_text = node['rawtext']
        #         has_rawtext = (raw_text != None)
        #     except Exception as e:
        #         print(e)
        #
        #     try:
        #         uri = node['refuri']
        #         has_uri = (uri != None)
        #     except Exception as e:
        #         print(e)
        #
        #     if has_rawtext:
        #         print("raw_text:", raw_text)
        #         trans = self.translate_text(raw_text, include_origin_in_translation=True)
        #     elif is_doc:
        #         print("refuri:", uri)
        #         trans = self.translate_text(n, include_origin_in_translation=True)
        #         # if trans:
        #         #     lead = ':doc:`'
        #         #     msg = n.astext()
        #         #     find_text="{}{}".format(lead, msg)
        #         #     replace_text = "{}{} -- {} ".format(lead, trans, msg)
        #         #     self.current_msg = re.sub(find_text, replace_text, self.current_msg)
        #         #     print(find_text, replace_text, "self.current_msg", self.current_msg)
        #     else:
        #         print("NOT RAW")
        #         trans = self.translate(n, include_origin_in_translation=True)

    def visit_literal(self, node):
        print("visit_literal")
        # self.printNode(node)
        # for index, n in enumerate(node):
        #     self.printNode(n)
        #     msg = node.astext()
        #     packed_ref = cm.PACKED_REF.search(msg)
        #     has_packed_ref = (packed_ref != None)
        #     if has_packed_ref:
        #         print("has_packed_ref:[{}]".format(packed_ref))
        #         rs, re, rm1, rm2 = cm.patternMatchAsParts(cm.PACKED_REF, msg)
        #         trans = self.translate_text(rm1)
        #     else:
        #         trans = self.translate_text(msg)

    def invisible_visit(self, node):
        # type: (nodes.Node) -> None
        """Invisible nodes should be ignored."""
        pass
# --------------------------------------------------------------

gtr = GTR() #Google translator

def dump_po(filename, catalog):
    dirname = os.path.dirname(filename)
    if not os.path.exists(dirname):
        os.makedirs(dirname)

    # Because babel automatically encode strings, file should be open as binary mode.
    with io.open(filename, 'wb') as f:
        pofile.write_po(f, catalog, width=4096)

def isInRefList(reflist, entry):
    is_empty_list = (not reflist or len(reflist) == 0)
    if is_empty_list:
        return False

    is_empty_entry = (not entry or len(entry) == 0)
    if is_empty_entry:
        return False

    start_post_list = []
    end_post_list = []
    extract_list = []

    es, ee, eorig, eextract = entry
    for s, e, orig, extract in reflist:
        is_entry = (s == es) and (e == ee) and (orig == eorig) and (eextract == extract)
        if is_entry:
            continue

        start_post_list.append(s)
        end_post_list.append(e)
        extract_list.append(extract)

    # print("es, ee, eorig, eextract")
    # print(es, ee, eorig, eextract)
    #
    # pp(start_post_list)
    # pp(end_post_list)
    # pp(orig_list)

    is_in = (es in start_post_list) and (ee in end_post_list) and (eextract in extract_list)
    # print("is_in", is_in)

    return is_in


def doctree_resolved(app, doctree, docname):

    def replaceRefTrans(msg, ref_trans_list):
        print("replaceRefTrans:")
        print("msg:[{}]".format(msg))
        print("ref_trans_list:")
        pp(ref_trans_list)

        orig_msg = str(msg)
        for w_start, w_end, ref, orig, trans in reversed(ref_trans_list):
            msg = msg.replace(orig, trans)
            print("trans_text:[{}]".format(trans))
            print("new_msg:[{}]".format(msg))

        print(orig_msg, " |==>| ", msg)
        return msg

    build_dir = "build/rstdoc"
    po_vi_dir = "locale/vi/LC_MESSAGES"

    po_file_path="{}.po".format(docname)
    local_path = os.path.dirname(os.path.abspath( __file__ ))
    blender_docs_path = os.path.dirname(local_path)

    rst_output_location = os.path.join(blender_docs_path, build_dir)
    output_path = os.path.join(rst_output_location, po_file_path)

    print_separator(output_path)

    # is_debug = "/about/contribute/guides/markup_guide" in output_path
    # if not is_debug:
    #     return


    # for node in doctree.traverse():
    #     is_literal = (isinstance(node, nodes.literal))
    #     if (is_literal):
    #         print("is_literal, type:", type(node))
    #         print("is_literal, text:", node.astext())

    #trans_doctree = doctree.deepcopy()

    cat = Catalog()
    visitor_inited = False
    empty_node_visitor = None

    visitor_inited = False
    visitor = None

    for node, msg in extract_messages(doctree):
        msg = unescape(msg).strip()

        if (not visitor_inited):
            visitor = TranslationNodeVisitor(node.document)
            visitor_inited = True

        #setVars(self, node, msg, trans):
        visitor.setVars(node, msg, None)
        try:
            node.walk(visitor)
        except Exception as e:
            print(e)
            raise e


    print_separator(output_path)

def setup(app):
    # app.connect('builder-inited', builder_inited)
    # app.connect('source-read', source_read)
    app.connect('doctree-resolved', doctree_resolved)
    return {
        'version': '0.1',
        'parallel_read_safe': True,
        'parallel_write_safe': True,
    }

Reply via email to