コード例 #1
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getVocabularySection(self, inputString):
        # we only need 4 entries, but because of double entries we might end up
        #   with some being merged, also need +1 to show the "more entries"
        #   play safe and select 10
        # TODO true contains
        dictResult = self._dictionary.getForHeadword(
            '*' + inputString + '*', orderBy=['Weight'], limit=10)

        htmlList = []
        if dictResult:
            htmlList.append('<table class="vocabulary">')
            # don't display alternative if the charString is found
            #   in the given string
            showAlternative = lambda charString, _: \
                    (charString.find(inputString) < 0)
            htmlList.append(self._getVocabularyTable(dictResult[:4],
                useAltFunc=showAlternative))
            htmlList.append('</table>')

            if len(dictResult) > 4:
                htmlList.append(
                    '<a class="meta" href="#lookup(%s)">%s</a>' \
                        % (util.encodeBase64('vocabulary' \
                            + ':' + inputString), gettext('All entries...')))
        else:
            htmlList.append('<span class="meta">%s</span>' \
                % gettext('No entries found'))

        return '\n'.join(htmlList)
コード例 #2
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getOtherVocabularySearchSection(self, inputString):
        """
        Gets a list of vocabulary entries containing the given inputString.
        """
        htmlList = []

        # TODO use caching
        dictResult = self._dictionary.getFor('*' + inputString + '*',
            orderBy=['Weight'])

        if dictResult:
            htmlList.append('<table class="otherVocabulary">')
            htmlList.append('<tr><td colspan="3"><h3>%s</h3></td></tr>' \
                % gettext('Other matches'))
            augmentedInput = '*' + inputString + '*'
            htmlList.append(self._getVocabularyTable(dictResult,
                useAltFunc=lambda x, y: \
                    self._matchesInput(inputString, y) \
                    and not self._matchesInput(inputString, x)))
            htmlList.append('</table>')

        else:
            htmlList.append('<span class="meta">%s</span>' \
                    % gettext('No matches found'))

        return '\n'.join(htmlList)
コード例 #3
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getCharacterWithSamePronunciationSection(self, inputString):
        """Gets a list of characters with the same pronunciation."""
        dictResult = self._searchDictionarySamePronunciationAs(inputString)

        # group by reading and character
        charDict = {}
        for char, charAlt, reading, translation in dictResult:
            if reading not in charDict:
                charDict[reading] = {}
            if char not in charDict[reading]:
                charDict[reading][char] = []
            charDict[reading][char].append(
                (char, charAlt, reading, translation))

        if charDict:
            html = ''
            for reading in sorted(charDict.keys(), reverse=True):
                characterLinks = []
                for char in charDict[reading]:
                    characterLinks.append('<li><span class="character">' \
                        + '<a class="character" href="#lookup(%s)">%s</a>' \
                            % (util.encodeBase64(char),  char) \
                        + '</span>%s</li>' % self._getDictionaryInfo(char,
                            charDict[reading][char]))
                html += '<h3>%s</h3>' % reading \
                    + '<ul>%s</ul>' % ' '.join(characterLinks)

            return '<div class="samereading">' + html + '</div>'
        else:
            return '<span class="meta">%s</span>' % gettext('No entries found')
コード例 #4
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
 def getEduTwLink(self, charString):
     if len(charString) == 1:
         relLink = self._dictionary.charDB.getCharacterIndex(charString, 'EduTwIndex')
         if relLink:
             link = u'http://www.edu.tw/files/site_content/M0001/bishuen/' \
                 + relLink
             return link, (u'常用國字標準字體筆順手冊 (%s)'
                 % gettext('edu.tw stroke order handbook'))
コード例 #5
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getStrokeOrderSection(self, inputString):
        strokeOrderFunc, _ \
            = self.STROKE_ORDER_SOURCES[self.BIG_STROKE_ORDER_TYPE]
        strokeOrder = strokeOrderFunc(self, inputString)

        if strokeOrder:
            return '<span class="bigstrokeorder">%s</span>' % strokeOrder
        else:
            return '<span class="meta">%s</span>' % gettext('no information')
コード例 #6
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getFullVocabularySection(self, inputString):
        """
        Gets a list of dictionary entries with exact matches and matches
        including the given character string.
        """
        dictResult = self._dictionary.getForHeadword(inputString)

        htmlList = []
        htmlList.append('<table class="fullVocabulary">')

        # exact matches
        htmlList.append('<tr><td colspan="3"><h3>%s</h3></td></tr>' \
            % gettext('Dictionary entries'))
        if dictResult:
            showAlternative = lambda charString, _: (charString != inputString)
            htmlList.append(self._getVocabularyTable(dictResult,
                useAltFunc=showAlternative))
        else:
            htmlList.append(
                '<tr><td colspan="3"><span class="meta">%s</span></td></tr>' \
                    % gettext('No exact matches found'))

        # other matches
        # TODO true contains
        dictResult = self._dictionary.getForHeadword('*' + inputString + '*',
            orderBy=['Reading'])

        if dictResult:
            htmlList.append('<tr><td colspan="3"><h3>%s</h3></td></tr>' \
                % gettext('Other matches'))

            # don't display alternative if the charString is found in the
            #   given string
            showAlternative = lambda charString, _: \
                    (charString.find(inputString) < 0)
            htmlList.append(self._getVocabularyTable(dictResult,
                useAltFunc=showAlternative))

        htmlList.append('</table>')

        return '\n'.join(htmlList)
コード例 #7
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getSimilarVocabularySearchSection(self, inputString):
        """
        Gets a list of vocabulary entries with pronunciation similar to the
        given string.
        """
        htmlList = []

        dictResult = self._dictionary.getForSimilarReading(inputString,
            orderBy=['Reading'])

        if dictResult:
            htmlList.append('<table class="similarVocabulary">')
            htmlList.append('<tr><td colspan="3"><h3>%s</h3></td></tr>' \
                % gettext('Similar pronunciations'))
            htmlList.append(self._getVocabularyTable(dictResult))
            htmlList.append('</table>')

        else:
            htmlList.append('<span class="meta">%s</span>' \
                % gettext('No matches found'))

        return '\n'.join(htmlList)
コード例 #8
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getDecompositionTreeSection(self, inputString):
        """Gets a tree of components included in the given character."""
        def getLayer(decompTree, isSubTree=False):
            if type(decompTree) != type(()):
                char = decompTree
                if char != u'?':
                    if char in seenEntry:
                        return '<span class="entry">' \
                            + '<span class="character">%s</span>' % char \
                            + '</span>'
                    else:
                        seenEntry.add(char)
                        return '<span class="entry"><span class="character">' \
                            + '<a class="character" href="#lookup(%s)">%s</a>' \
                                % (util.encodeBase64(char),  char) \
                            + '</span>%s</span>' % self._getDictionaryInfo(char)
                else:
                    return '<span class="entry meta">%s</span>' \
                        % gettext('unknown')
            else:
                layout, char, tree = decompTree
                if char:
                    if isSubTree:
                        head = layout + '<span class="character">' \
                            + '<a class="character" href="#lookup(%s)">%s</a>' \
                                % (util.encodeBase64(char),  char) \
                            + '</span>' \
                            + self._getDictionaryInfo(char)
                    else:
                        # don't show dictionary information for the root element
                        head = layout \
                            + '<span class="character">%s</span>' % char
                else:
                    head = layout

                subLayer = []
                for idx, entry in enumerate(tree):
                    cssClass = 'decomposition'
                    if idx == len(tree) - 1:
                        cssClass += ' last'
                    subLayer.append('<li class="%s">%s</li>' \
                        % (cssClass, getLayer(entry, isSubTree=True)))
                return '<span class="entry">%s<ul>%s</ul></span>' \
                    % (head, ''.join(subLayer))

        decompTree = self._dictionary.charDB.getCharacterDecomposition(inputString)
        if decompTree:
            seenEntry = set()
            return '<div class="tree">%s</div>' % getLayer(decompTree)
        else:
            return '<span class="meta">%s</span>' % gettext('No entry found')
コード例 #9
0
ファイル: componentview.py プロジェクト: cburgmer/eclectus
    def getComponentSearchResult(self, components,
        includeEquivalentRadicalForms=False, includeSimilarCharacters=False):
        """Gets a list of characters containing the given components."""
        chars = self.charDB.getCharactersForComponents(components,
            includeEquivalentRadicalForms=includeEquivalentRadicalForms,
            includeSimilarCharacters=includeSimilarCharacters)

        if chars:
            charLinks = []
            for char in chars:
                charLinks.append(
                    '<a class="character" href="#lookup(%s)">%s</a>' \
                        % (util.encodeBase64(char), char))
            html = '<span class="character">%s</span>' % ' '.join(charLinks)
        else:
            html = '<p class="meta">%s</p>' % gettext('No entries')

        return html, len(chars)
コード例 #10
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
        def getLayer(decompTree, isSubTree=False):
            if type(decompTree) != type(()):
                char = decompTree
                if char != u'?':
                    if char in seenEntry:
                        return '<span class="entry">' \
                            + '<span class="character">%s</span>' % char \
                            + '</span>'
                    else:
                        seenEntry.add(char)
                        return '<span class="entry"><span class="character">' \
                            + '<a class="character" href="#lookup(%s)">%s</a>' \
                                % (util.encodeBase64(char),  char) \
                            + '</span>%s</span>' % self._getDictionaryInfo(char)
                else:
                    return '<span class="entry meta">%s</span>' \
                        % gettext('unknown')
            else:
                layout, char, tree = decompTree
                if char:
                    if isSubTree:
                        head = layout + '<span class="character">' \
                            + '<a class="character" href="#lookup(%s)">%s</a>' \
                                % (util.encodeBase64(char),  char) \
                            + '</span>' \
                            + self._getDictionaryInfo(char)
                    else:
                        # don't show dictionary information for the root element
                        head = layout \
                            + '<span class="character">%s</span>' % char
                else:
                    head = layout

                subLayer = []
                for idx, entry in enumerate(tree):
                    cssClass = 'decomposition'
                    if idx == len(tree) - 1:
                        cssClass += ' last'
                    subLayer.append('<li class="%s">%s</li>' \
                        % (cssClass, getLayer(entry, isSubTree=True)))
                return '<span class="entry">%s<ul>%s</ul></span>' \
                    % (head, ''.join(subLayer))
コード例 #11
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getCharacterWithComponentSection(self, inputString):
        """Gets a list of characters with the given character as component."""
        chars = self._dictionary.charDB.getCharactersForComponents([inputString])

        if inputString in chars:
            chars.remove(inputString)

        if chars:
            characterLinks = []
            for char in chars:
                #characterLinks.append(
                    #'<a class="character" href="#lookup(%s)">%s</a>' \
                        #% (util.encodeBase64(char), char))
                characterLinks.append('<li><span class="character">' \
                    + '<a class="character" href="#lookup(%s)">%s</a>' \
                        % (util.encodeBase64(char),  char) \
                    + '</span>%s</li>' % self._getDictionaryInfo(char))
            return '<div class="components"><ul>%s</ul></div>' \
                % ' '.join(characterLinks)
        else:
            return '<span class="meta">%s</span>' % gettext('No entries found')
コード例 #12
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def _getContainedEntitiesSection(self, inputString, dictResult):
        """
        Gets a list of dictionary entries for single characters of the given
        character string.
        """
        def sortDictionaryResults(x, y):
            charStringA, charStringAltA, _, _ = x
            charStringB, charStringAltB, _, _ = y
            a = inputString.find(charStringA)
            if a < 0:
                a = inputString.find(charStringAltA)
            b = inputString.find(charStringB)
            if b < 0:
                b = inputString.find(charStringAltB)
            if a == b:
                return len(charStringA) - len(charStringB)
            else:
                return a - b

        htmlList = []
        if dictResult:
            dictResult.sort(sortDictionaryResults)

            htmlList.append('<table class="containedVocabulary">')
            # don't display alternative if the charString is found
            #   in the given string
            showAlternative = lambda charString, _: \
                    (inputString.find(charString) < 0)
            htmlList.append(self._getVocabularyTable(dictResult,
                useAltFunc=showAlternative, smallSpacing=True))
            htmlList.append('</table>')

        else:
            htmlList.append('<span class="meta">%s</span>' \
                % gettext('No entries found'))

        return '\n'.join(htmlList)
コード例 #13
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
 def getCantoDictLink(self, charString):
     link = u'http://www.cantonese.sheik.co.uk/dictionary/search/' \
         + '?searchtype=1&text=%s' % charString
     return link, gettext('CantoDict Cantonese-Mandarin-English dictionary')
コード例 #14
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
 def getUnihanLink(self, charString):
     if len(charString) == 1:
         link = u'http://www.unicode.org/cgi-bin/GetUnihanData.pl?' \
             + u'codepoint=%s' % hex(ord(charString)).replace('0x', '')
         return link, gettext('Unicode Unihan database')
コード例 #15
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
 def getWWWJDICLink(self, charString):
     link = u'http://www.csse.monash.edu.au/~jwb/cgi-bin/' \
         + u'wwwjdic.cgi?1MUJ%s' % charString
     return link, gettext('WWWJDIC Japanese-English dictionary')
コード例 #16
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
 def getCEDICTLink(self, charString):
     link = u'http://us.mdbg.net/chindict/chindict.php?wdqchs=%s' \
         % charString
     return link, gettext('MDBG Chinese-English dictionary')
コード例 #17
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
 def getAudio(filePath):
     return (' <a class="audio" href="#play(%s)">%s</a>'
         % (urllib.quote(filePath.encode('utf8')), gettext('Listen')))
コード例 #18
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
 def getHanDeDictLink(self, charString):
     link = u'http://www.chinaboard.de/chinesisch_deutsch.php?' \
         + u"sourceid=konqueror-search&skeys=%s" % charString
     return link, gettext('HanDeDict Chinese-German dictionary')
コード例 #19
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getVocabularySearchSection(self, inputString):
        """
        Gets the search results for the given string including exact maches
        and a shortened list of similar results and results including the given
        string.
        """
        htmlList = []
        htmlList.append('<table class="search">')

        # exact hits
        exactDictResult = self._dictionary.getFor(inputString,
            orderBy=['Weight'])

        if exactDictResult:
            htmlList.append('<tr><td colspan="3"><h3>%s</h3></td></tr>' \
                % gettext('Matches'))
            # match against input string with regular expression
            htmlList.append(self._getVocabularyTable(exactDictResult,
                useAltFunc=lambda x, y: \
                    self._matchesInput(inputString, y) \
                    and not self._matchesInput(inputString, x)))


        # similar pronunciation
        similarDictResult = self._dictionary.getForSimilarReading(
            inputString, orderBy=['Weight'], limit=5)

        if similarDictResult:
            htmlList.append('<tr><td colspan="3"><h3>%s</h3></td></tr>' \
                % gettext('Similar pronunciations'))
            htmlList.append(self._getVocabularyTable(similarDictResult[:4]))

            if len(similarDictResult) > 4:
                htmlList.append('<tr><td colspan="3">' \
                    + '<a class="meta" href="#lookup(%s)">%s</a>' \
                        % (util.encodeBase64('similar' + ':' \
                            + inputString), gettext('All entries...'))
                    + '</td></tr>')


        # other matches
        # TODO optimize and include other matches in exact run, after all
        #   translation will be all searched with LIKE '% ... %'
        otherDictResult = self._dictionary.getFor('*' + inputString + '*',
            orderBy=['Weight'])

        if otherDictResult:
            htmlList.append('<tr><td colspan="3"><h3>%s</h3></td></tr>' \
                % gettext('Other matches'))
            augmentedInput = '*' + inputString + '*'
            htmlList.append(self._getVocabularyTable(otherDictResult[:4],
                useAltFunc=lambda x, y: \
                    self._matchesInput(inputString, y) \
                    and not self._matchesInput(inputString, x)))

            if len(otherDictResult) > 4:
                htmlList.append('<tr><td colspan="3">' \
                    + '<a class="meta" href="#lookup(%s)">%s</a>' \
                        % (util.encodeBase64('othervocabulary' + ':' \
                            + inputString), gettext('All entries...'))
                    + '</td></tr>')

        # handle 0 result cases
        if not exactDictResult:
            if not similarDictResult and not otherDictResult:
                htmlList.append('<tr><td colspan="3">'\
                    + '<span class="meta">%s</span>' \
                        % gettext('No matches found') \
                    + '</td></tr>')
            else:
                htmlList.insert(0, '<tr><td colspan="3">'\
                    + '<span class="meta">%s</span>' \
                        % gettext('No exact matches found') \
                    + '</td></tr>')

        htmlList.append('</table>')

        return '\n'.join(htmlList)
コード例 #20
0
ファイル: dictionaryview.py プロジェクト: cburgmer/eclectus
    def getMeaningSection(self, inputString):
        """
        Gets a list of entries for the given character string, sorted by reading
        with annotated alternative character writing, audio and vocab handle.
        """
        def getAudio(filePath):
            return (' <a class="audio" href="#play(%s)">%s</a>'
                % (urllib.quote(filePath.encode('utf8')), gettext('Listen')))
                #audioHtml = ' <a class="audio" href="#" onclick="new Audio(\'%s\').play(); return false;">%s</a>' \
                    #% (urllib.quote(filePath.encode('utf8')), gettext('Listen'))
                #audioHtml = ' <audio src="%s" id="audio_%s" autoplay=false></audio><a class="audio" href="#" onClick="document.getElementById(\'audio_%s\').play(); return false;">%s</a>' \
                    #% (urllib.quote(filePath.encode('utf8')), reading, reading, gettext('Listen'))

        readings = []
        translations = {}
        translationIndex = {}
        alternativeHeadwords = []
        alternativeHeadwordIndex = {}

        # TODO index calculation is broken, e.g. 说
        # TODO cache
        dictResult = self._dictionary.getForHeadword(inputString)

        for idx, entry in enumerate(dictResult):
            _, charStringAlt, reading, translation = entry

            # get unique sorted readings
            if reading not in readings:
                readings.append(reading)

            # save translation, take care of double entries
            if reading not in translations:
                translations[reading] = []
                translationIndex[reading] = idx
            if translation not in translations[reading]:
                translations[reading].append(translation)

            # save alternative headword, save link to translation
            if charStringAlt not in alternativeHeadwords:
                alternativeHeadwords.append(charStringAlt)
                alternativeHeadwordIndex[charStringAlt] = []
            # save link to translation
            alternativeHeadwordIndex[charStringAlt].append(
                translations[reading].index(translation))

        htmlList = []
        # show alternative headword when a) several different ones exist,
        #   b) several entries exist, c) different to headword
        if self.showAlternativeHeadwords and alternativeHeadwords \
            and (len(alternativeHeadwords) > 1 \
                or inputString not in alternativeHeadwords):
            altHeadwordHtml = []
            for altHeadword in alternativeHeadwords:
                if len(inputString) > 1:
                    className = "word"
                else:
                    className = "character"

                entry = '<span class="%s">' % className \
                    + '<a class="character" href="#lookup(%s)">%s</a></span>' \
                        % (util.encodeBase64(altHeadword), altHeadword)

                if len(readings) > 1 or len(translations[readings[0]]) > 1:
                    indices = [str(i + 1) for i \
                        in alternativeHeadwordIndex[altHeadword]]
                    altHeadwordHtml.append('<li>' + entry \
                        + '<span class="alternativeHeadwordIndex">%s</span>' \
                            % ' '.join(indices) \
                        + '</li>')
                else:
                    altHeadwordHtml.append('<li>%s</li>' % entry)

            htmlList.append('<p><ul class="alternativeHeadword">%s</ul></p>' \
                % ''.join(altHeadwordHtml))

        # show entries
        if readings:
            htmlList.append('<table class="meaning">')

            for reading in readings:
                # get audio if available
                #filePath, audioHtml = getAudio(reading)
                filePath, audioHtml = ('', '') # TODO
                # get reading
                readingEntry = '<a class="reading" href="#lookup(%s)">%s</a>' \
                    % (util.encodeBase64(reading),
                        self._getReadingRepresentation(reading,
                            forceBlocksOfFor=False))
                # get translations
                translationEntries = []
                for translation in translations[reading]:
                    translationEntries.append('<li class="translation">' \
                        + '<a class="addVocabulary" ' \
                        + 'href="#addvocab(%s;%s;%s;%s)"></a>' \
                            % (util.encodeBase64(inputString),
                                util.encodeBase64(reading),
                                util.encodeBase64(translation),
                                util.encodeBase64(filePath)) \
                        + self._getTranslationRepresentation(translation) \
                        + '</li>')
                translationString = ''.join(translationEntries)
                # create table entry
                htmlList.append('<tr class="meaningEntry">' \
                            + '<td class="reading">%s%s</td>' \
                                % (readingEntry, audioHtml) \
                            + '<td><ol start="%d">%s</ol></td>' \
                                % (translationIndex[reading] + 1,
                                    translationString) \
                            + '</tr>')

            htmlList.append('</table>')
        else:
            htmlList.append('<span class="meta">%s</span>' \
                % gettext('No dictionary entries found'))

        return '\n'.join(htmlList)
コード例 #21
0
ファイル: radicalview.py プロジェクト: cburgmer/eclectus
    def getCharacterForRadical(self, radicalIndex, includeAllComponents=False):
        """Gets a list of characters classified under the given radical."""
        # group by residual stroke count
        characterGroups = self.charDB.getCharacterListForKangxiRadicalIndex(
            radicalIndex, includeAllComponents=includeAllComponents)

        htmlList = []

        # show main radical form
        htmlList.append('<h3>%s</h3>' \
            % (gettext('Radical %(radical_index)d') \
                % {'radical_index': radicalIndex}))

        charLinks = []
        for strokeCount in sorted(characterGroups['radical'].keys()):
            for char in sorted(characterGroups['radical'][strokeCount]):
                charLinks.append('<span class="character">' \
                    + '<a class="character" href="#lookup(%s)">%s</a>' \
                        % (util.encodeBase64(char), char) \
                    + '</span>')

        htmlList.append(' '.join(charLinks))

        radicalEntryDict = self.charDB.getRadicalDictionaryEntries()
        _, meaning = radicalEntryDict.get(radicalIndex, (None, None))
        if meaning:
            htmlList.append(' <span class="translation">%s</span>' % meaning)

        radicalForms = self.charDB.kangxiRadicalForms
        _, strokeCount, _, _ = radicalForms[radicalIndex]
        if strokeCount:
            htmlList.append(' <span class="strokecount">(%s)</span>' \
                % (ngettext('%(strokes)d stroke', '%(strokes)d strokes',
                    strokeCount) % {'strokes': strokeCount}))


        htmlList.append('<h3>%s</h3>' % gettext('Characters'))

        # list sorted by residual stroke count
        if not characterGroups[None]:
            htmlList.append('<span class="meta">%s</span>' \
                % gettext('no results found for the selected character domain'))
        else:
            htmlList.append('<table class="searchResult">')
            for strokeCount in sorted(characterGroups[None].keys()):
                if type(strokeCount) not in (type(0), type(0L)):
                    # sort out non stroke count groups
                    continue

                htmlList.append('<tr>' \
                    + '<th class="strokeCount">+%s</th><td>' % strokeCount)
                charLinks = []
                for char in sorted(characterGroups[None][strokeCount]):
                    charLinks.append('<span class="character">' \
                        + '<a class="character" href="#lookup(%s)">%s</a>' \
                            % (util.encodeBase64(char), char) \
                        + '</span>')
                htmlList.append(' '.join(charLinks))

                htmlList.append('</td></tr>')

            # Add characters without stroke count information
            if None in characterGroups[None]:
                htmlList.append('<tr>' \
                    + '<th class="strokeCount">%s</th><td>' % gettext('Unknown'))
                charLinks = []
                for char in sorted(characterGroups[None][None]):
                    charLinks.append('<span class="character">' \
                        + '<a class="character" href="#lookup(%s)">%s</a>' \
                            % (util.encodeBase64(char), char) \
                        + '</span>')
                htmlList.append(' '.join(charLinks))

                htmlList.append('</td></tr>')

            htmlList.append('</table>')

        return "\n".join(htmlList)