OpenDict Add-Ons Development HOWTO

Introduction

OpenDict is free multiplatform dictionary. More information about it can be found on OpenDict website.

This document is written for developers who want to make easy-installable OpenDict dictionaries.

Warning: It is not necessary to make OpenDict dictionary if you have a dictionary file in Slowo, Mova or DICT format. Such dictionaries can be used right now by selecting Dictionaries -> Install Dictionary from File from OpenDict menu.

Types of OpenDict Dictionaries

OpenDict has two types of dictionaries: plain (simple) dictionaries and plugin (complex) dictionaries. Plain dictionaries consists of dictionary file (type of that dictionary must be supported by OpenDict) and description file in XML format. Plugin dictionaries consists of Python module with code that handles search process and description file in XML format; it may also have dictionary file which is processed by Python module mentioned above.

Plain dictionaries are simple and handy. It is very easy to install them using OpenDict itself. If you have dictionary file (format of that dictionary must be supported by OpenDict) and want to attach some information to it, like the name, the author, the description, you may want to make plain dictionary.

If you have more complex task, like search the web, etc, you may want to make a plugin for OpenDict. The plugin is a chunk of code written in Python programming language that OpenDict attaches to itself at runtime.

The next sections of this document will describe how to make plain dictionaries and plugins.

Plain Dictionary Example

Assume we have a small dictionary file named mydict.dwa in Slowo format:

above = ant ; virš ;
abroad = visur ; užsienyje ;
acoustic = akustinis ;
acquaint = pranešti ;

Say we want to call this dictionary "My Personal Dictionary" and attacht a description "This is my personal dictionary. It is very small, but it is not the size that matters :)" to it. Each plain dictionary must have XML description file named config.xml, otherwise it will be treated as invalid dictionary. So we write an XML file called config.xml with our favorite text or XML editor:

<?xml version='1.0' encoding='UTF-8'?>
<plain-dictionary>
  <format>slowo</format>
  <name>My Personal Dictionarys</name>
  <version>0.1</version>
  <authors>
     <author name="Your Name" email="your@email.tdl"/>
  </authors>
  <path>mydict.dwa</path>
  <md5>9c62810c32ca20fe018b79987789daef</md5>
  <encoding>UTF-8</encoding>
  <description><![CDATA[
     This is my personal dictionary. It is very small, but it is not the
     size that matters :)
  ]]>
  </description>
</plain-dictionary>

As you can see, a little more information must be added to description (i.e. configuration) file. Here is a short description of each section:

XML tag Description
format Dictionary format. OpenDict supports the following formats:
  • slowo -- Slowo format
  • mova -- Mova format
  • dict -- DICT format
TODO: describe all supported format somewhere
name Name of the dictionary. It will be shown in the Dictionaries menu in OpenDict window.
version Version value is very important. It shows the freshness of your dictionary. The more recent the dictionary, the greater version value must be set. For example: 0.1, 0.2, 0.3, etc; or 1, 2, 3, etc.
author

The author of the dictionary. Notice that author tag is inside authors tag, because there may be several authors of the dictionary. So add as may author tags as you want, but make them the childs of the authors tag.

This tag is a bit complicated, because you may not be the author of the dictionary file you are using. If so, you may treat the author tag as maintainance tag and write your as maintainer name inside it. In addition to this, you should write the name of the author in the description tag mentioned below.

path Path to the dictionary file. It may be an absolute (i.e. full) path to the dictionary file or relative path. If you write full path, dictionary would be taken from there. Buf if you write only the name of the dictionary (i.e. mydict.dwa), the dictionary will be treated to be located at $DICTDIR/file/mydict.dwa, where $DICTDIR is directory where you dictionary is located, for example /home/mjoc/.opendict/dictionaries/plain/mydict.dwa/file/mydict.dwa. If you are going to distribute dictionary file with OpenDict plain dictionary, you want to write only the file name inside path tag.
md5 This is an MD5 checksum value of the dictionary file (i.e. mydict.dwa). This MD5 code is used to determine changes of the dictionary file. That means user is able to modify dictionary file and OpenDict will recreate index table before using that dictionary next time. If you want to get MD5 checksum value of you dictionary file, execute the following command on your system (Linux, BSD) shell:
        $ md5sum myfile.dwa
	9c62810c32ca20fe018b79987789daef  myfile.dwa
    
You can see the command and the output above. Just copy that 32-chars checksum to your XML file. This is quite unfriendly, so I will think about easer ways some day. Nevertheless, we are developers today.
encoding Character encoding of the dictionary file. Examples: UTF-8, UTF-16, ISO-8859-1, ISO-8859-13, etc.
description Description of your dictionary. You should not remove that <![CDATA[ ... ]]> tag, because it lets you to write any text inside using even XML (HTML) tags like 1 + 1 < 1 or <myemail@abcdef.tdl>

The last file you need is an index file. This file contains index table of the dictionary describing in what position what letter begins. Index makes search a lot faster.

I do not recommend writing index file using your fingers and the keyboard :), so we will use OpenDict to make one for ourselves. Lets now make a directory tree containing these files and directories:

mydict.dwa/
    |
    +-- conf/
    |     |
    |     +-- config.xml
    |
    +-- data/
    |     
    |
    +-- file/
          |
          +-- mydict.dwa

As you see, the root direcory is called mydict.dwa, the same as dictionary file is called. This is the rule. Now move that directory to the directory where all the plain dictionaries are located. On my machine I would do:

    mjoc@kumo:~/tmp/dict-factory$ mv mydict.dwa/ ~/.opendict/dictionaries/plain/

After that you should start OpenDict and load the dictionary you've just made. If everything goes well, you will be informed about reindexing the dictionary. Press OK and, if everything goes well, you will have index.xml file located at data/ directory. On my machine the full path would be /home/mjoc/.opendict/dictionaries/plain/mydict.dwa/data/index.xml. Now the directory tree look in a way like that:

mydict.dwa/
    |
    +-- conf/
    |     |
    |     +-- config.xml
    |
    +-- data/
    |     |
    |     +-- index.xml
    |
    +-- file/
          |
          +-- mydict.dwa

Now we have all the files needed. They are located at $DICTDIR. The last step is to make a ZIP archive of that directory. Notice that that ZIP file must contain the dictionary directory (i.e. mydict.dwa/) itself, not only files inside it. To zip the directory, I would do:

    mjoc@kumo:~/tmp/dict-factory$ cd ~/.opendict/dictionaries/plain/
    mjoc@kumo:~/.opendict/dictionaries/plain$ zip -r MyDictionary-0.1.zip mydict.dwa/
    mjoc@kumo:~/.opendict/dictionaries/plain$ mv MyDictionary-0.1.zip ~
    mjoc@kumo:~/.opendict/dictionaries/plain$ cd

Now file MyDictionary-0.1.zip can be found at my home direcory (/home/mjoc/). That's all. Now you have made a dictionary that can be installed by everyone using OpenDict by selecting Dictionaries -> Install Dictionary from File from the menu.

Simple Plugin Example

In this section I am going to give an example of simple OpenDict plugin dictionary. Good example is a network dictionary plugin that fetches translations from the web and processed them locally.

At first we have to create file called plugin.xml. The contents of this file may be similar to this one:

<?xml version="1.0" encoding="UTF-8"?>
<plugin type="dictionary">
   <name>Network Test</name>
   <version>0.1</version>
   <authors>
      <author name="Martynas Jocius" email="mjoc@akl.lt" />
   </authors>
   <module lang="Python">mydict.py</module>
   <encoding>UTF-8</encoding>
   <uses-word-list>False</uses-word-list>
   <opendict-version>0.5.7</opendict-version>
   <python-version>2.3</python-version>
   <platforms>
      <platform name="Linux" />
      <platform name="BSD" />
      <platform name="Windows" />
   </platforms>
   <description>
   Example plugin dictioary. Does nothing.
   </description>
</plugin>

As you may already noticed, some XML tags are the same as in the previous config.xml example. There is the description of new tags, like encoding, module, etc.

XML tag Description
module Main Python module file name.
encoding Character encoding of the result string that plugin module returns (examples include UTF-8, ISO-8859-15, etc)
uses-word-list This should be set to True if dictionary needs word list to be shown, False otherwise. If dictionary uses word list, it must return a list of alternative words in addition with translation string (see below for more information)
opendict-version The lowest OpenDict version plugin requires, for example 0.5.1, 0.5.7, etc. This is important when plugin structure is different from one that old OpenDict versions provide (for example 0.5.1 and 0.5.7 plugin structure differs a lot)
python-version The lowest Python version that plugin requires.
python-version The lowest Python version that plugin requires.
platforms Parent node for platform tag.
platform This tag with attribute name value X means that this plugin is tested and works on platform X. For example, Linux, BSD, MacOS. Currently not used

Now we should write the main module in Python programming language. Module file name is mydict.py as we called it in plugin.xml. The following code might be correct OpenDict plugin:

#!/usr/bin/env python

#
# MyDict 0.1
# Copyright (c) 2005 Matynas Jocius <mjoc@akl.lt>
#
# Simple plugin dictionary for OpenDict.
#
# This code is licensed under the GNU GPL v2.
#

"""
Simple OpenDict plugin module
"""

import sys
import httplib
import urllib


def init(libraryPath):
    """Return dictionary instance"""

    sys.path.insert(0, libraryPath)

    return MyDict()



class MyDict:
    """MyDict plugin class"""
    
    def __init__(self):
        """Initialize variables"""

        # This trick is needed to have accessible modules from
        # OpenDict library
        from lib import errortype, meta

        self.errorModule = errortype
        self.metaModule = meta

        
    def search(self, word):
        """Search and return HTML code."""

        print type(word), len(word)

        result = self.metaModule.SearchResult()

        try:
            self.conn = httplib.HTTPConnection("mjoc.sig.lt")
            self.conn.request("GET", "/index.html")
            response = self.conn.getresponse()
            data = response.read()

            trans = "<html><body><h3>"

            if word in data:
                trans += "Word <i>%s</i> was found on " \
                         "http://mjoc.sig.lt/index.html" % word
            else:
                trans += "Word <i>%s</i> was not found on " \
                         "http://mjoc.sig.lt/index.html" % word

            trans += "</h3></body></html>"

            result.setTranslation(trans)

        except Exception, e:
            import traceback
            traceback.print_exc()

            result.setError(self.errorModule.INTERNAL_ERROR)

            return result

        return result

TODO: describe how to write the class and other details.

To make an installable plugin file in ZIP archive format, move plugin.xml and mydict.py into some directory (i.e. mydict-0.1) and zip that directory. After performing these actions your new OpenDict plugin will be ready to be installed.

Conclusion

TODO: This document is very short and fuzzy. It must be improved in the future.