<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">--- ../../../multilang.cvs/moin/MoinMoin/logger.py	Wed Jan 22 13:44:11 2003
+++ logger.py	Wed Jan 15 19:03:41 2003
@@ -0,0 +1,234 @@
+"""
+    MoinMoin - generic log
+
+    Copyright (c) 2000, 2001, 2002 by Florian Festi
+    All rights reserved, see COPYING for details.
+        
+"""
+
+class TextLogger:
+    """ generic text log
+
+        lots of the functionallity is still untested, use with care
+    """
+    def __init__(self, filename, format = None, reversed = 0, offset = None):
+        """
+        """
+        self.index = 0                   # for next(), peek() - user space
+        self.__filename = filename
+        self.filter = None
+        self.__raw = None                # raw lines
+        self.__data = None               # parsed lines
+        self.__byte_offset = 0           # length of skiped part
+        self.__line_offset = 0           # number skiped lines
+        self.__reversed = reversed
+        self.__format = format           # None or "[sif]*"
+        if self.__format:
+            self.__formatstring = self.__format_string(self.__format)
+        if offset:
+            (self.__line_offset, self.__byte_offset) = offset
+
+    def sanityCheck(self):
+        """ Check for editlog file access.
+        """
+        if not os.access(self.filename, os.W_OK):
+            return "The edit log '%s' is not writable!" % (self.filename,)
+        return None
+
+    def addEntry(self, *data):
+        """ append data to the log file
+        """
+        logfile = open(self.__filename, 'a+')
+        entry = self.__encode_line(data)
+        try:
+            # fcntl.flock(logfile.fileno(), fcntl.LOCK_EX)
+            logfile.seek(0, 2)                  # to end
+            logfile.write(entry)
+        finally:
+            # fcntl.flock(logfile.fileno(), fcntl.LOCK_UN)
+            logfile.close()
+        return entry
+
+    def __format_string(self, format):
+        """ Calculate string used for conversion data -&gt; log line 
+        """
+        result = ''
+        for c in format:
+            if not c in ['s', 'i', 'f']:
+                raise ValueError
+            result = result + "%" + c + '\t'
+        result = result[:-1] + '\n'
+        return result
+
+    def __encode_line(self, data):
+        """ converts data to line in the log file
+        """
+        from types import *
+        if self.__format:
+            return self.__formatstring % data
+        # Use Pythonsyntax
+        else:
+            return `data`
+                                
+    def __decode_line(self, line):
+        """ converts a line from the log file zu a list of items
+        """
+        if self.__format:
+            fields = string.split(string.strip(line), '\t')
+            result = []
+            for i in range(len(fields)):
+                if self.__format[i] == 's':
+                    result.append(fields[i])
+                elif self.__format[i] == 'i':
+                    try:
+                        result.append(int(fields[i]))
+                    except ValueError:
+                        result.append(0)
+                else: # 'f'
+                    try:
+                        result.append(float(fields[i]))
+                    except ValueError:
+                        result.append(0.0)
+            # fill missing fields
+            for c in self.__format[len(fields):]:
+                if c == 's': result.append('')
+                elif c == 'i': result.append(0)
+                elif c == 'f': result.append(0.0)
+                
+        # Python format
+        else:
+            try:
+                return eval(line[:-1])
+            except:
+                return ""
+
+    def __read_from_file(self):
+        """ load log file
+        """
+        file = open(self._filename, 'r')
+        self.__raw = file.readlines()
+        self.__data = map(self.__decode_line, self.__raw)
+
+    def __set_entry(self, index):
+        """ called by next() and peek() to set attributes as side effect
+            index is the internal index for self.__data, index is valid or None
+            this is intended to be used for child classes
+        """ 
+        pass
+
+    def __key_to_index(self, key, truncate = 1):
+        """ calculates the intern index for __data
+            if truncate the functions returns None if index is out of range
+        """
+        length = len(self.__data) + self.__line_offset
+        offset = self.__line_offset
+        if key &lt; 0: key = key + length
+        if reversed:
+            key = length - key - 1
+        if truncate and (key &lt; offset or key &gt;= length):
+            return None      
+        else: return key
+
+### direct access
+
+    def read(self):
+        """ returns a list of all entrys which are lists of items
+        """
+        if not self.__data:
+            self.__read_from_file()
+        if self.filter:
+            result = filter(self.__data, self.filter)
+        else:
+            result = self.__data[:]
+        if self.__reversed: result.reverse()
+        return result
+
+    def __getitem__(self, key):
+        """ returns one line as list of items 
+        """
+        if not self.__data:
+            self.__read_from_file()
+        index = self.__key_to_index(key)
+        if index != None:
+            return self.__data[index]
+        else:
+            return None
+
+    def keys(self):
+        """ returns list with all valid indices
+        """
+        if self.__reversed:
+            return range(len(self.__data))
+        else:
+            return range(self.__line_offset,
+                         len(self.__data) + self.__line_offset)
+
+    def range(self):
+        """ returns tuple of first valid and first invalid index
+        """
+        if self.__reversed:
+            return (0,len(self.__data))
+        else:
+            return (self.__line_offset,
+                    len(self.__data) + self.__line_offset)
+
+                                
+   
+    def getOffset(self, line = None):
+        """ returns a tuple off line number and a offset object
+            (the byte offset for text logs). This tuple can be passed to
+            the constructor.
+        """
+        if line == None:
+            line = self.index
+        index = self.__key_to_index(line, truncate = 0)
+        if index &gt; len(self.__data):
+            index = len(self.__data)
+        if index &lt; 0:
+            return (self.__line_offset, self.__byte_offset)
+        bytes = 0
+        for l in self.__raw[:line]:
+            bytes = bytes + len(l)
+        return (self.__line_offset + line, self.byte_offset + bytes) 
+
+##### Iterator functions
+
+    def next(self, offset = 1):
+        """ returns next line as a list of items
+            self.__set_entry is called (see there)
+        """
+        if not self.__data:
+            self.__read_from_file()
+        self.index = self.index + offset
+        index = self.__key_to_index(self.index)
+        self.__set_entry(index)
+        if index != None: return self.__data[index]
+        else: return None
+
+    def peek(self, offset=0):
+        """ returns a line offset away from the actual line
+            self.__set_entry is called (see there)
+        """
+        if not self.__data:
+            self.__read_from_file()
+        index = self.__key_to_index(self.index + offset)
+        self.__set_entry(index)
+        if index != None: return self.__data[index]
+        else: return None
+
+    def reset(self):
+        """ sets the index to the first line and returns it  as list of items
+            the first line may not be number 0 if there is an offset
+        """
+        if not self.__data:
+            self.__read_from_file()
+        if self.__reversed:
+            self.index = 0
+        else:
+            self.index = self.__line_offset
+        index = self.__key_to_index(self.index)
+        self.__set_entry(index)
+        if index != None: return self.__data[index]
+        else: return None
+
+#   self.index
--- ../../../multilang.cvs/moin/MoinMoin/multilang.py	Tue Jan 14 22:00:44 2003
+++ multilang.py	Fri Jan 17 19:36:16 2003
@@ -8,12 +8,15 @@
 """
 
 # Imports
-from MoinMoin import config, wikiutil
+from MoinMoin import config, wikiutil, logger
+from MoinMoin.i18n import _
 import os.path
 
 # translated page operations
 def title_search(needle, languages = None, extended=None):
-    """ ??? """
+    """ searches in all or the given languages
+        if extended translations of found pages are also found
+    """
     import re
     
     if not languages:
@@ -77,7 +80,7 @@
         translation_file = new_translation_file(page_name)
         set_translation_file(page_name, translation_file)
         set_translation_file(pages[0], translation_file)
-        add_translation(translation_file, config.interwikilink+':'+page_name)
+        add_translation(translation_file, config.interwikiname+':'+page_name)
         add_translation(translation_file, pages[0])
     else: # ambigous or no translations
         # raise IOError ????? This triggers when creating a new page when there is no translation yet. Should not be.
@@ -93,9 +96,9 @@
     translation_file = get_translation_file(page_name)
     if translation_file:
         translations = read_translations(translation_file)
-        iwlen = len(config.interwikilink)            
+        iwlen = len(config.interwikiname)            
         for translation in translations:               
-            if translation[0:iwlen] == config.interwikilink:
+            if translation[0:iwlen] == config.interwikiname:
                 translations.remove(translation)
         return translations
     else:
@@ -109,18 +112,17 @@
     page_name = inter_language_link(_page_name)
     to_page = inter_language_link(_to_page)
     if not page_name:
-        errmsg = _page_name + " is not a valid Interwikilink. "
+        errmsg = _page_name + _(" is not a valid Interwikilink. ")
     if not to_page:
-        errmsg = errmsg + _to_page + " is not a valid Interwikilink. "
+        errmsg = errmsg + _to_page + _(" is not a valid Interwikilink. ")
     if errmsg:
         return errmsg
     
     translation_file = get_translation_file(to_page)
     # page already has translations
     if translation_file:
-        errmsg = "added myself to" + to_page
         if add_translation(translation_file, page_name):
-            errmsg = to_page + " has already a translation in your language"
+            errmsg = to_page + _(" has already a translation in your language")
             return errmsg
         # delete myself from my old translationfile
         my_translation_file = get_translation_file(page_name)
@@ -133,12 +135,11 @@
         # do we have translations
         if translation_file:
             if add_translation(translation_file, to_page):
-                errmsg = ( 'This page "' + page_name +
-                           '" has already a translation in this language')
+                errmsg = ( _('The page "') + page_name +
+                           _('" has already a translation in this language'))
             else:
                 set_translation_file(to_page, translation_file)
         else:
-            errmsg = 'new translation file'
             # generate new translation file
             translation_file = new_translation_file(page_name)
             set_translation_file(page_name, translation_file)
@@ -148,19 +149,19 @@
     return errmsg
 
 def unset_translation(_page_name):
-    """ ??? """
+    """ removes translation for given page """
     errmsg = ''
     # test page_name
     page_name = inter_language_link(_page_name)
     if not page_name:
-        return _page_name + " is not a valid Interwikilink. "
+        return _page_name + _(" is not a valid Interwikilink. ")
 
     translation_file = get_translation_file(page_name)
     if translation_file:
         remove_translation(translation_file, page_name)
         set_translation_file(page_name, None)
     else:
-        errmsg = 'no translation'
+        errmsg = _('no translation')
     return errmsg
 
 ##### Internal functions #######################
@@ -178,10 +179,12 @@
                 return lang + ':' + interwiki[1]
         return None
     else: # is a local page
-        return config.interwikilink + ':' + page_name
+        return config.interwikiname + ':' + page_name
         
 def get_translation_file(pagename):
-    """ return file name or None """
+    """get group file name from "per page" file
+       returns file name or None
+    """
     lang_file = get_language_file(pagename)
     if not lang_file:
         return None
@@ -194,7 +197,7 @@
         return None
 
 def set_translation_file(pagename, translationfilename):
-    """ ??? """
+    """ set group file name into "per page" file """
     lang_file = get_language_file(pagename)
     if translationfilename:
         if not os.path.exists(os.path.dirname(lang_file)):
@@ -209,7 +212,7 @@
 
 # translation group file operations 
 def read_translations(translation_file):
-    """ ??? """
+    """ get all interwikinames form group file """
     translation_file = os.path.join(config.multilingual_dir, translation_file)
     try:
         f = open(translation_file, 'r')
@@ -221,32 +224,36 @@
     return translations
                                             
 def add_translation(translationfile, interwikilink):
-    """ ??? """
-    translationfile = os.path.join(config.multilingual_dir, translationfile)
-    if os.path.exists(translationfile):
-        f = open(translationfile, 'r')
+    """ Add interwikilink to group file """
+    translationfilename = os.path.join(config.multilingual_dir, translationfile)
+    if os.path.exists(translationfilename):
+        f = open(translationfilename, 'r')
         translations = f.readlines()
         f.close()
         # test if there already is a translation in our language
         wiki, page = wikiutil.split_wiki(interwikilink)
         if not wiki:
-            wiki = config.interwikilink
+            wiki = config.interwikiname
             interwikilink = wiki + ':' + interwikilink
         log = 'X'
         iwlen = len(wiki)
         for translation in translations:
-            log = log + translation
             if translation[0:iwlen] == wiki:
                 return 1
-    f = open(translationfile, 'a')
-    f. write(interwikilink + '\n')
+    f = open(translationfilename, 'a')
+    f.write(interwikilink + '\n')
     f.close()
+    mtime = os.path.getmtime(translationfilename)
+    
+    log = getLog()
+    log.addEntry(mtime, interwikilink, translationfile, "SET")
+    
 
 def remove_translation(translationfile, interwikilink):
-    """ ??? """
-    translationfile = os.path.join(config.multilingual_dir, translationfile)
-    if os.path.exists(translationfile):
-        f = open(translationfile, 'rw')
+    """ remove interwikiname form group file  """
+    translationfilename = os.path.join(config.multilingual_dir, translationfile)
+    if os.path.exists(translationfilename):
+        f = open(translationfilename, 'rw')
         translations = f.readlines()
         f.close()
         for translation in translations:
@@ -254,14 +261,22 @@
                 translations.remove(translation)
 
         if len(translations)&gt;0:
-            f = open(translationfile, 'w')
+            f = open(translationfilename, 'w')
             f.writelines(translations)
             f.close()
+            mtime = os.path.getmtime(translationfilename)
         else:
-            os.remove(translationfile)
+            os.remove(translationfilename)
+            mtime = os.path.getmtime(config.multilingual_dir)
+        log = getLog()
+        log.addEntry(mtime, interwikilink, translationfile, "REMOVE")
 
 def new_translation_file(page_name):
-    """ returns unique aund quoted filename """
+    """ returns unique and quoted filename """
+    # use Pagename only
+    interwiki = page_name.split(':', 1)
+    page_name = interwiki[-1]
+    
     translationfile = os.path.join(config.multilingual_dir,
                                    wikiutil.quoteFilename(page_name))
     newtranslationfile = translationfile
@@ -271,10 +286,11 @@
         i = i + 1
     return os.path.basename(newtranslationfile)
 
-# access to external wikis
+# access to files in "external" wikis
 
 def get_interwiki_filename(interwikilink):
-    """ returns directory or filename """
+    """ returns a page file or a text directory belonging to a interwikiname
+    """
     interwiki = interwikilink.split(':', 1)
     if len(interwiki) == 2:
         if config.languages.has_key(interwiki[0]):
@@ -287,7 +303,9 @@
                             wikiutil.quoteFilename(interwiki[0]))
 
 def get_language_file(interwikilink):
-    """ returns directory or filename """
+    """ returns file containing the name of the translation group
+        this is the "per page" file
+    """
     interwiki = interwikilink.split(':', 1)
     if len(interwiki) == 2:
         if config.languages.has_key(interwiki[0]):
@@ -307,7 +325,7 @@
     """ returns HTML Source for a link like "[en]" or "[en] FrontPage" """
     tag, interwiki, tail = wikiutil.resolve_wiki(page_name)
     if not tag:
-        tag = config.interwikilink
+        tag = config.interwikiname
         interwiki = ''
     url = interwiki + wikiutil.quoteWikiname(tail)
     if show_name:
@@ -316,3 +334,12 @@
         result = '&lt;a href="%s"&gt;[%s]&lt;/a&gt;' % (url, tag.lower())
     return result
 
+# Logging
+
+def getLog():
+    from MoinMoin import logger
+    return logger.TextLogger(os.path.join(config.multilingual_dir, 'multilang.log'), format= "isss")
+
+    
+    
+
--- ../../../multilang.cvs/moin/MoinMoin/Page.py	Tue Jan 14 22:00:39 2003
+++ Page.py	Sat Jan 18 18:41:58 2003
@@ -167,9 +167,8 @@
                         flags = flags + ' ' + multilang.language_link(translation, 0)
             # if none found show similar pages
             else:
-                pass
                 other_languages = config.languages.keys()
-                other_languages.remove(config.interwikilink)
+                other_languages.remove(config.interwikiname)
                 translations = multilang.title_search(self.page_name,
                                                       other_languages,
                                                       extended=None)
@@ -519,9 +518,9 @@
             search = search[:-1]
             pages = multilang.title_search(search, None, 1)
             i = 0
-            langlength = len(config.interwikilink)
+            langlength = len(config.interwikiname)
             while i &lt; len(pages):
-                if pages[i][0:langlength] == config.interwikilink:
+                if pages[i][0:langlength] == config.interwikiname:
                     del pages[i]
                 else:
 		    i = i + 1
@@ -578,7 +577,11 @@
         else:
             return self.page_name
 
-    def translation(self, request):
+    def translation_menu(self, request, msg=None, **keywords):
+        """
+        multilang extention
+        Print TranlationMenu for this Page.  
+        """
         request.clock.start('send_page')
         import cgi
         from MoinMoin.util import pysupport
@@ -601,11 +604,19 @@
         webapi.http_headers(request)
         sys.stdout.write(doc_leader)
 
-        wikiutil.send_title(page_name)
-        from MoinMoin import multilang        
+        wikiutil.send_title(page_name, msg=msg, pagename=self.page_name)
+        from MoinMoin import multilang
+        
+        # Back to page
+        print self.formatter.paragraph(1)
+        print self.formatter.url(wikiutil.quoteWikiname(self.page_name),
+                                 _("Back to ") + page_name)
+        print self.formatter.paragraph(0)
+        
+        # Existing Translations
+        print self.formatter.heading(2, 'Translations of %s' % page_name)
         translations = multilang.get_translations(page_name)
         if len(translations) &gt; 0:
-            print self.formatter.heading(2, 'Translations of %s' % page_name)
             print self.formatter.bullet_list(1)
             for translation in translations:
                 tag, interwiki, tail = wikiutil.resolve_wiki(translation)
@@ -613,10 +624,6 @@
                 # Link
                 print multilang.language_link(translation)
                 # Link for removing
-#                print (' ( &lt;a href="%(page_name)s?' +
-#                       'action=TranslationMenu&amp;do=unset&amp;page=%(tag)s:%(tail)s"&gt;' +
-#                       'remove from group&lt;/a&gt; ) &lt;/li&gt;\n' ) % vars()
-
                 print " ( " 
                 print wikiutil.link_tag("%s?action=TranslationMenu&amp;do=unset&amp;page=%s" % (
                     wikiutil.quoteWikiname(self.page_name),
@@ -632,6 +639,7 @@
                 wikiutil.quoteWikiname(self.page_name)),
                                     _("Remove this page from group"))
             print self.formatter.paragraph(0)
+
         # Show similar Pages
         if request.form.has_key("text_title"):
             searchtext = request.form["text_title"].value
@@ -644,8 +652,8 @@
         if self.inter_wiki_link() in pages:
             pages.remove(self.inter_wiki_link())
         pages.sort()
+        print self.formatter.heading(2,'Similar Pages')
         if len(pages) &gt; 0:
-            print self.formatter.heading(2,'Similar Pages')
             print self.formatter.bullet_list(1)
             for p in pages:
                 tag, interwiki, tail = wikiutil.resolve_wiki(p)
@@ -657,25 +665,26 @@
                 tag + ":" + wikiutil.quoteWikiname(tail)),
                 _("Add"))
                 print " ) "
-#                print (' ( &lt;a href="%(page_name)s?' +
-#                       'action=TranslationMenu&amp;do=set&amp;page=%(tag)s:%(tail)s"&gt;' +
-#                       'Add&lt;/a&gt; ) &lt;/li&gt;\n' ) % vars()
                 print self.formatter.listitem(0)
             print self.formatter.bullet_list(0)
-
-            print """Search 
+        # Searchbox
+        print self.formatter.paragraph(1)
+        print _("Search")
+        print """ 
 &lt;form method="POST" action="%s"&gt;
     &lt;input type="hidden" name="action" value="TranslationMenu"&gt;
     &lt;input type="text" name="text_title" value="%s" size="30"&gt;
     &lt;input type="image" src="/wiki/img/moin-search.gif" name="button_title"
     alt="[?]" hspace="3" width="12" height="12" border="0"&gt;
 &lt;/form&gt;""" % ( page_name, searchtext )
+        print self.formatter.paragraph(0)
 
         # Insert new Translations directly
-        print "&lt;h2&gt;Add new Translation&lt;/h2&gt;"
-        print "Insert Interwikilink and press Go"
+        print self.formatter.heading(2,_("Add new Translation"))
+        print _("Insert Interwikilink and press Go")
         print macro.execute('SetTranslation', '')
 
+        wikiutil.send_footer(request, self.page_name, showpage=1)
         # end document output
         sys.stdout.write(self.formatter.endDocument())
         request.clock.stop('send_page')
--- ../../../multilang.cvs/moin/MoinMoin/wikimacro.py	Thu Aug  1 20:07:52 2002
+++ wikimacro.py	Wed Jan  8 14:34:59 2003
@@ -247,7 +247,7 @@
         row(_('MoinMoin Version'), _('Release %s [Revision %s]') % (version.release, version.revision))
         if ftversion:
             row(_('4Suite Version'), ftversion)
-        row(_('Number of pages'), len(wikiutil.getPageList(config.text_dir)))
+        row(_('Number of pages'), _('%i (%i bytes)') % (len(wikiutil.getPageList(config.text_dir)), wikiutil.getTextSize(config.text_dir)))
         row(_('Number of backup versions'), len(wikiutil.getBackupList(config.backup_dir, None)))
         edlog = editlog.EditLog(self.request)
         row(_('Entries in edit log'), _("%(logcount)s (%(logsize)s bytes)") %
--- ../../../multilang.cvs/moin/MoinMoin/wikiutil.py	Tue Jan 14 22:00:45 2003
+++ wikiutil.py	Tue Jan 14 22:12:16 2003
@@ -211,6 +211,19 @@
         result.append(file)
     return map(unquoteFilename, result)
 
+def getTextSize(text_dir):
+    """ Returns bytes used by all pages, except for "CVS" directories,
+    hidden files (leading '.') and temp files (leading '#')
+    """
+    pages = os.listdir(text_dir)
+    result = 0
+    for file in pages:
+        if file[0] in ['.', '#'] or file in ['CVS']: continue
+        try:
+            result = result + os.path.getsize(os.path.join(text_dir, file))
+        except os.error:
+            pass
+    return result
 
 def getPageDict(text_dir):
     """ Return a dictionary of page objects for all pages,
</pre></body></html>