Translate Toolkit & Pootle

Tools to help you make your software local

User Tools

This project has been completed before the release of version 0.3, and the current development versions of Virtaal mostly follow this design.


This is the specification for the major architectural changes implemented for Virtaal 0.3. The main aim of these changes is to create a stable, robust and easy-to-use platform from which all the future changes can be easily implemented. For this purpose it has been decided to use a MVC architecture.

This page has been copied and adapted from the draft.



To reach the goals stated in the introduction above we will be implementing a MVC architecture in the code. See the diagram below for the proposed architectural structure.



Virtaal's MVC architecture


Views making up the GUI.


With a basic understanding of the MVC pattern as well as knowledge of Virtaal's features, the diagram should be reasonably self-explanitory. The following description contains notes about unexpected, unclear or new concepts introduced.

The Store group in the diagram represents the model, view and controller that is related to store-level activities. In terms of the GUI, the StoreView is the main gtk.TreeView widget as it is in Virtaal 0.2. The StoreModel is a basic wrapper for basic translation store which (mainly) handles the loading, saving and parsing of translation files.

Similarly the Unit group represents the unit-level components. The UnitView specifically represents the GUI of the unit editor (the selected unit) as it is in Virtaal 0.2.

The Mode MVC-triplet alters the StoreCursor in the StoreController that specifies which units are usable in the currently selected mode. This cursor is used by the StoreController and/or UnitController.

The MainController object serves as proxy for communications where no “official” channel is available. For example the StoreController gets its reference to the UnitController instance via the MainController.


Extensions can be done in one of three ways:

  • Extending relevant, existing component(s). This is typically how basic functionality will be implemented.
  • As separate MVC modules. Using this approach, a feature (or extension) creates its own model(s), view(s) and/or controller. These components then connect to the signals they are interested in, in order to connect themselves to the system. This should be the preferred method for bigger, more complicated features such as translation memory.
  • As plug-ins. Separate classes (possibly also with a MVC design) that are dynamically loaded and connects to signals of the existing components in order to connect to the system. This approach should be used by smaller, non-critical features. See the plug-ins section below for more information on writing plug-ins.


Currently there is not any plug-in support Virtaal yet, so this section will be completed as plug-in support is finished.


This section contains some notes about specific components.


  • There are a lot of direct calls (marked with a FIXME) which should be discussed (ex. self.controller.main_controller.store_controller.unit_controller)
  • There are parts of the code that were exempted from following the strict definition of MVC. The first part that comes to mind is the UndoController that contains 5 lines of Gtk+ code. Yes, it should actually be in a view object, but creating a whole new class for only those 5 lines seem to be a bit too extreme.


  • Modes' selected() and unselected() methods do not take any parameters, because we don't want to make any assumptions about what the mode does. If a mode needs any information, it can collect that via its connection to ModeController and then to MainController.
  • BaseMode, and so also all other modes, do not inherit from GObjectWrapper, because, as “dynamic” pieces of code, it is not condsidered safe (or necessary) to connect to a mode's event(s). This can, of course, easily be changed later.
  • All widgets that a mode adds to ModeView.mode_box MUST be contained in the mode's self.widgets list to make sure that it can be removed when the mode is unselected.

Search mode

Contains some minor bugs:

  • Match highlighting disappears with undo.
  • On some systems with Compiz enabled, it is impossible to use the mouse to go back to the search entry once it has left there. This is because (for some odd reason) Compiz causes the window to fire a configure-event event and that indirectly throws focus back to the first target text box.


Store model

  • StoreModel._get_valid_units() adjusts all stats to be relative to stats['total']. That is, stats['total'] is accepted as a list of valid unit indexes. Thus all stats are changed to be relative to the list of valid units. This is potentially a bad thing to do, although I can't of a reason at the moment.
  • There is NO direct access to the actual translation store outside of StoreModel.


  • The code in files like, and should be moved to an appropriate view.

Base view

  • Shouldn't it inherit from GObjectWrapper?

Unit view

  • Making the UnitView the gtk.CellEditable and gtk.Eventbox itself, in stead of a factory for such an object, might have been a bit overkill.


Store controller

  • Isn't StoreCursor more a part of StoreModel than StoreController?

Unfinished files

The following files are currently either unused or are still being integrated into Virtaal:


Source Code

This section contains specifications for all source code-related issues. Please add any missing info.

Naming conventions


As per PEP 8 class names are written in camel case, starting with a capital letter.


As per PEP 8, as well as existing conventions in the Translate Toolkit and Virtaal, variable names are all-lower case and words should be split with underscores.

Names of variables representing Gtk+ widgets should have a prefix describing the type of widget it represents. Here are some prefixes:

btn gtk.Button
cmb gtk.ComboBox
mnu gtk.MenuItem
tvw gtk.TreeView
txt gtk.TextView
wnd gtk.Window


  • Lines containing only comments or documentation strings should not be exceed 80 characters.
  • Long lines containing code should be formatted to maximise readability.
  • As a rule there should be only one class per file. Exceptions are allowed in cases where there are small, related classes grouped into a single file.
  • When in doubt, refer to PEP 8
  • If still in doubt, follow the conventions used so far.
  • If still in doubt, ask a dev!


  • Comments should be written while coding and not afterwards.
  • Missing features, obvious bugs or other important notes should immediately be marked with a FIXME, TODO or XXX mark in a comment.
  • Refrain from adding obvious comments except where used to label separate blocks of code.

Documentation strings

  • Epydoc-compatible document strings should be added where possible. This includes file- and class-level docstrings.
  • Inside classes at least all public and weak-private (one leading underscore) methods should be documented.
  • Method and function documentation strings must at least specify type parameters (the @type directive) and the return value if not None, except where these are very obvious.


  • Relative imports should not be used. This allows for much more clarity where scope of an imported class/function/variable is concerned.
  • Imports should always be grouped in the following order (separated by a blank line):
    • System/global module
    • Inter-Virtaal / inter-module
    • Intra-module (other files in the same module)


  • Even though it is not time-efficient to write tests for absolutely everything, there should at least be tests for the most important functionality of a class/module.
  • Tests should be grouped into test classes that test either a specific (large and important) class or a specific module.

File Layout

This is section is only applicable to the virtaal/ source sub-directory, seeing as the rest of the directory structure is serving us quite well.

Related code should definitely be grouped together into modules and sub-modules. Here are some possibilities:

  • Create sub-directories for models, views and controllers and put the files containing the relevant classes in each of those directories. Example for unit-related class files: models/, views/, controllers/
  • Create a separate (sub-)module for each MVC group of files/classes. This would mean the creation of at least the store, unit and mode sub-directories. Example for unit-related class files: unit/, unit/, unit/

Note that there is no mention of a plug-ins directory, because it has not been decided if plug-ins will be supported.


API documentation should be generated from the epydoc documentation strings in the source code. Other, more descriptive documentation should be maintained on the wiki.

Implementation Planning

All implementation reuses as much code as possible from Virtaal 0.2 in order to save development time.

Phase 1

  • Number of developers: 1
  • Estimated time needed: 5 days
  • Description: This phase consists of creating basic implementations of the following components (in roughly the order they appear in):
    • MainWindow
    • StoreController, StoreModel, StoreView (relatively parallel)
    • UnitController, UnitModel, UnitView (relatively parallel)

Phase 2

  • Number of developers: 1 or more
  • Estimated time needed: 3 days
  • Description: Implement all extra functionality from Virtaal 0.2. Here are some of the specific sub-goals for this phase:
    • Implement all mode-related classes. This includes creating ModeCursors and using them for navigation.
    • Implement undo functionality using StoreView and UnitView.


  • Undo
  • Modes
    • Search and replace
    • Incomplete
  • Spell checking
  • AutoCorrection/AutoCompletion
  • Add comments and context fields
  • Test formats other than PO Tested with basic XLIFF files.
  • Update headers - ask user for team info See related bug below.
  • Write tests.
  • Generate docs
  • Use unit-level gettargetlanguage() in stead of the store-level equivalent.


  • Mode bar visible even if no file is loaded.
  • “Save as…” should be inactive until a file is loaded.
  • First unit in a file is not selected on load.
  • Pressing Enter in a target does not move focus to the next plural textview.
  • If the first plural form is changed, the change is not visible after switching to a different unit. Problem was much bigger than mentioned. No changes to plurals were saved because of multistring's suckage.
  • Recent files not updating.
  • Editing area does not respond to changes in window size. Could not reproduce
  • Widget heights are not 100% correct for single-row units: too much space at the bottom.
  • Opening a second file does not work.
  • Excessive flickering when changing units.
  • Without specifying your translator e-mail address, each time a file is saved, a contributor heading is added regardless of whether there is one (or more) already. This is probably related to the checks in