Index: src/translator_fa.h
===================================================================
--- src/translator_fa.h	(revision 642)
+++ src/translator_fa.h	(working copy)
@@ -32,7 +32,7 @@
 #define HtmlDivEnd          QCString("</div>")
 
 
-class TranslatorPersian : public Translator
+class TranslatorPersian : public TranslatorAdapter_1_5_4
 {
   public:
 
Index: src/translator_fi.h
===================================================================
--- src/translator_fi.h	(revision 642)
+++ src/translator_fi.h	(working copy)
@@ -78,7 +78,7 @@
 #ifndef TRANSLATOR_FI_H
 #define TRANSLATOR_FI_H
 
-class TranslatorFinnish : public Translator
+class TranslatorFinnish : public TranslatorAdapter_1_5_4
 {
   public:
     /*! This method is used to generate a warning message to signal
Index: src/translatordecoder.h
===================================================================
--- src/translatordecoder.h	(revision 642)
+++ src/translatordecoder.h	(working copy)
@@ -707,7 +707,15 @@
     QCString trTypeConstraints()
     { return toUtf8(m_translator->trTypeConstraints()); }
 
+    QCString trDefineLocalSearch()
+    { return toUtf8(m_translator->trDefineLocalSearch()); }
+    QCString trUseWebServer()
+    { return toUtf8(m_translator->trUseWebServer()); }
 
+     QCString trLocalSearchResults(int numDocuments)
+    { return toUtf8(m_translator->trLocalSearchResults(numDocuments)); }
+
+
 //////////////////////////////////////////////////////////////////////////
   private:
     Translator *m_translator;
Index: src/translator_hr.h
===================================================================
--- src/translator_hr.h	(revision 642)
+++ src/translator_hr.h	(working copy)
@@ -71,7 +71,7 @@
 #ifndef TRANSLATOR_HR_H
 #define TRANSLATOR_HR_H
 
-class TranslatorCroatian : public Translator
+class TranslatorCroatian : public TranslatorAdapter_1_5_4
 {
   private:
         /*! to avoid macro redefinition from translator_cz.h */
Index: src/translator.h
===================================================================
--- src/translator.h	(revision 642)
+++ src/translator.h	(working copy)
@@ -1,12 +1,12 @@
 /******************************************************************************
  *
- * 
  *
+ *
  * Copyright (C) 1997-2008 by Dimitri van Heesch.
  *
  * Permission to use, copy, modify, and distribute this software and its
- * documentation under the terms of the GNU General Public License is hereby 
- * granted. No representations are made about the suitability of this software 
+ * documentation under the terms of the GNU General Public License is hereby
+ * granted. No representations are made about the suitability of this software
  * for any purpose. It is provided "as is" without express or implied warranty.
  * See the GNU General Public License for more details.
  *
@@ -35,35 +35,35 @@
   protected:
     /*! Returns the string converted from windows-1250 to iso-8859-2. */
     QCString Win1250ToISO88592(const QCString & sInput);
-    
+
     /*! Returns the string converted from iso-8859-2 to windows-1250. */
     QCString ISO88592ToWin1250(const QCString & sInput);
-    
+
     /*! Returns the string converted from koi8-r to windows-1251. */
     QCString Koi8RToWindows1251( const QCString & sInput );
 
     /*! Returns the string converted from windows-1251 to koi8-r. */
     QCString Windows1251ToKoi8R( const QCString & sInput );
-    
+
     /*! Returns the string converted from Japanese-EUC to SJIS. */
     QCString JapaneseEucToSjis( const QCString & sInput );
 
   public:
 
     /*! This method is used to provide warning message that is displayed
-     *  if the user chooses a language whose translation is not up to date. 
+     *  if the user chooses a language whose translation is not up to date.
      *  It is implemented by the adapter classes.
      */
     virtual QCString updateNeededMessage() { return ""; }
     virtual ~Translator() {}
-   
+
     // Please, have a look at comments inside the translator_en.h file
     // to learn the meaning of the following methods.  The translator_en.h
-    // file contains the TranslatorEnglish implementation, which is 
+    // file contains the TranslatorEnglish implementation, which is
     // always up-to-date (by definition).
-   
+
     // --- Language control methods -------------------
-    
+
     virtual QCString idLanguage() = 0;
     virtual QCString latexLanguageSupportCommand() = 0;
     virtual QCString idLanguageCharset() = 0;
@@ -109,14 +109,14 @@
     virtual QCString trRelatedPagesDescription() = 0;
     virtual QCString trModulesDescription() = 0;
     //virtual QCString trNoDescriptionAvailable() = 0;
-    
-    // index titles (the project name is prepended for these) 
 
+    // index titles (the project name is prepended for these)
+
     virtual QCString trDocumentation() = 0;
     virtual QCString trModuleIndex() = 0;
     virtual QCString trHierarchicalIndex() = 0;
     virtual QCString trCompoundIndex() = 0;
-    virtual QCString trFileIndex() = 0; 
+    virtual QCString trFileIndex() = 0;
     virtual QCString trModuleDocumentation() = 0;
     virtual QCString trClassDocumentation() = 0;
     virtual QCString trFileDocumentation() = 0;
@@ -155,17 +155,17 @@
 //////////////////////////////////////////////////////////////////////////
 // new since 0.49-990307
 //////////////////////////////////////////////////////////////////////////
-    
+
     virtual QCString trNamespaceList() = 0;
     virtual QCString trNamespaceListDescription(bool extractAll) = 0;
     virtual QCString trFriends() = 0;
-    
+
 //////////////////////////////////////////////////////////////////////////
 // new since 0.49-990405
 //////////////////////////////////////////////////////////////////////////
-    
+
     virtual QCString trRelatedFunctionDocumentation() = 0;
-    
+
 //////////////////////////////////////////////////////////////////////////
 // new since 0.49-990425
 //////////////////////////////////////////////////////////////////////////
@@ -176,7 +176,7 @@
 
     virtual QCString trFileReference(const char *fileName) = 0;
     virtual QCString trNamespaceReference(const char *namespaceName) = 0;
-    
+
     virtual QCString trPublicMembers() = 0;
     virtual QCString trPublicSlots() = 0;
     virtual QCString trSignals() = 0;
@@ -256,7 +256,7 @@
 //////////////////////////////////////////////////////////////////////////
 // new since 1.1.0
 //////////////////////////////////////////////////////////////////////////
-    
+
     virtual QCString trNote() = 0;
     virtual QCString trPublicTypes() = 0;
     virtual QCString trPublicAttribs() = 0;
@@ -284,7 +284,7 @@
     virtual QCString trAttention() = 0;
     virtual QCString trInclByDepGraph() = 0;
     virtual QCString trSince() = 0;
-    
+
 //////////////////////////////////////////////////////////////////////////
 // new since 1.1.5
 //////////////////////////////////////////////////////////////////////////
@@ -292,11 +292,11 @@
     virtual QCString trLegendTitle() = 0;
     virtual QCString trLegendDocs() = 0;
     virtual QCString trLegend() = 0;
-    
+
 //////////////////////////////////////////////////////////////////////////
 // new since 1.2.0
 //////////////////////////////////////////////////////////////////////////
-    
+
     virtual QCString trTest() = 0;
     virtual QCString trTestList() = 0;
 
@@ -325,11 +325,11 @@
     virtual QCString trPackages() = 0;
     //virtual QCString trPackageDocumentation() = 0;
     virtual QCString trDefineValue() = 0;
-    
+
 //////////////////////////////////////////////////////////////////////////
 // new since 1.2.5
 //////////////////////////////////////////////////////////////////////////
-    
+
     virtual QCString trBug() = 0;
     virtual QCString trBugList() = 0;
 
@@ -340,7 +340,7 @@
     virtual QCString trRTFansicp() = 0;
     virtual QCString trRTFCharSet() = 0;
     virtual QCString trRTFGeneralIndex() = 0;
-   
+
     // Translation of the word
 
     virtual QCString trClass(bool first_capital, bool singular) = 0;
@@ -355,7 +355,7 @@
 //////////////////////////////////////////////////////////////////////////
 // new since 1.2.7
 //////////////////////////////////////////////////////////////////////////
-        
+
     virtual QCString trAuthor(bool first_capital, bool singular) = 0;
 
 //////////////////////////////////////////////////////////////////////////
@@ -370,7 +370,7 @@
 
     virtual QCString trImplementedFromList(int numEntries) = 0;
     virtual QCString trImplementedInList(int numEntries) = 0;
-    
+
 //////////////////////////////////////////////////////////////////////////
 // new since 1.2.16
 //////////////////////////////////////////////////////////////////////////
@@ -382,7 +382,7 @@
 //////////////////////////////////////////////////////////////////////////
 
     virtual QCString trDeprecatedList() = 0;
-    
+
 //////////////////////////////////////////////////////////////////////////
 // new since 1.2.18
 //////////////////////////////////////////////////////////////////////////
@@ -399,7 +399,7 @@
     virtual QCString trStaticPackageMembers() = 0;
     virtual QCString trPackageAttribs() = 0;
     virtual QCString trStaticPackageAttribs() = 0;
-    
+
 //////////////////////////////////////////////////////////////////////////
 // new since 1.3.1
 //////////////////////////////////////////////////////////////////////////
@@ -414,6 +414,7 @@
     virtual QCString trSearchForIndex() = 0;
     virtual QCString trSearchResultsTitle() = 0;
     virtual QCString trSearchResults(int numDocuments) = 0;
+    virtual QCString trLocalSearchResults(int numDocuments) = 0;
     virtual QCString trSearchMatches() = 0;
 
 //////////////////////////////////////////////////////////////////////////
@@ -442,14 +443,14 @@
 //////////////////////////////////////////////////////////////////////////
 // new since 1.4.6
 //////////////////////////////////////////////////////////////////////////
-    
+
     virtual QCString trCallerGraph() = 0;
     virtual QCString trEnumerationValueDocumentation() = 0;
 
 //////////////////////////////////////////////////////////////////////////
 // new since 1.5.4
 //////////////////////////////////////////////////////////////////////////
-    
+
     virtual QCString trMemberFunctionDocumentationFortran() = 0;
     virtual QCString trCompoundListFortran() = 0;
     virtual QCString trCompoundMembersFortran() = 0;
@@ -476,6 +477,10 @@
     virtual QCString trSubprogram(bool first_capital, bool singular) = 0;
     virtual QCString trTypeConstraints() = 0;
 
+    virtual QCString trDefineLocalSearch() = 0;
+
+    virtual QCString trUseWebServer() = 0;
+
 };
 
 #endif
Index: src/searchindex.h
===================================================================
--- src/searchindex.h	(revision 642)
+++ src/searchindex.h	(working copy)
@@ -59,6 +59,7 @@
     SearchIndex();
     void setCurrentDoc(const char *name,const char *baseName,const char *anchor=0);
     void addWord(const char *word,bool hiPriority);
+    void writeJavaScriptIndex(const char *file);
     void write(const char *file);
   private:
     QDict<IndexWord> m_words;
Index: src/translator_cn.h
===================================================================
--- src/translator_cn.h	(revision 642)
+++ src/translator_cn.h	(working copy)
@@ -24,7 +24,7 @@
 */
 #define CN_SPC
 
-class TranslatorChinese : public Translator
+class TranslatorChinese : public TranslatorAdapter_1_5_4
 {
   public:
 		/*! Used for identification of the language. The identification
Index: src/libdoxygen.t
===================================================================
--- src/libdoxygen.t	(revision 642)
+++ src/libdoxygen.t	(working copy)
@@ -108,6 +108,15 @@
 search_php.h: search.php
 	cat search.php | $(TO_C_CMD) >search_php.h 
 
+local-search_js.h: local-search.js
+	cat local-search.js | $(TO_C_CMD) >local-search_js.h
+
+choose-search_js.h: choose-search.js
+	cat choose-search.js | $(TO_C_CMD) > choose-search_js.h
+
+local-search-globals_js.h: local-search-globals.js
+	cat local-search-globals.js | $(TO_C_CMD) > local-search-globals_js.h
+
 doxygen_css.h: doxygen.css
 	cat doxygen.css | $(TO_C_CMD) >doxygen_css.h 
 
Index: src/translator_mk.h
===================================================================
--- src/translator_mk.h	(revision 642)
+++ src/translator_mk.h	(working copy)
@@ -32,7 +32,7 @@
 #ifndef TRANSLATOR_MK_H
 #define TRANSLATOR_MK_H
 
-class TranslatorMacedonian : public Translator
+class TranslatorMacedonian : public TranslatorAdapter_1_5_4
 {
   public:
 
Index: src/libdoxygen.pro.in
===================================================================
--- src/libdoxygen.pro.in	(revision 642)
+++ src/libdoxygen.pro.in	(working copy)
@@ -1,6 +1,6 @@
 #
-# 
 #
+#
 # Copyright (C) 1997-2008 by Dimitri van Heesch.
 #
 # Permission to use, copy, modify, and distribute this software and its
@@ -62,6 +62,9 @@
                 latexdocvisitor.h \
 		latexgen.h \
                 lockingptr.h \
+                local-search_js.h \
+                choose-search_js.h \
+                local-search-globals_js.h \
 		logos.h \
 		mandocvisitor.h \
 		mangen.h \
Index: src/local-search.js
===================================================================
--- src/local-search.js	(revision 0)
+++ src/local-search.js	(revision 0)
@@ -0,0 +1,560 @@
+﻿/*! local-search.js
+ * Searches a Doxygen index file and displays matching pages,
+ * on a local filing system without HTTP.
+ *
+ * @author Mitchell Fraser
+ *
+ */
+
+
+/* give the short names used to reduce the size of
+  local-search-index.js more meaningful names */
+var theIndex = x;
+
+var words = w;
+
+var urls = u;
+
+function computeIndex(word)
+{
+
+  // Simple hashing that allows for substring search
+  if (word.length <2) return -1;
+  // high char of the index
+  hi = word.charCodeAt(0);
+  if (hi == 0) return -1;
+  // low char of the index
+  lo = word.charCodeAt(1);
+  if (lo==0) return -1;
+
+
+  return hi*256+lo;
+}
+
+
+function getParam( param )
+{
+    //function copied from
+    //http://www.netlobo.com/url_query_string_javascript.html
+    // use permitted by comment in
+    // http://www.netlobo.com/comments/url_query_string_javascript
+
+    param = param.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
+
+    var regexS = "[\\?&]" + param + "=([^&#]*)";
+    var regex = new RegExp( regexS );
+    var results = regex.exec( window.location.href );
+    if( results == null )
+        return "";
+    else
+        return results[1];
+}
+
+
+var g_header;
+
+var g_footer;
+
+var g_top;
+
+var scriptElements;
+
+function stringOf(obj)
+{
+    var theString = "";
+    var attr;
+    for (attr in obj)
+    {
+        theString += attr + " : " +  obj[attr] + "\n";
+    }
+    return theString
+
+}
+
+
+function saveHeader()
+{
+    headerElem = document.getElementsByTagName("head")[0];
+    if (null == headerElem)
+        g_header = "Error, could not find \"head\" element.";
+    else
+    {
+        //we replace the "local-search-index.js" with ""
+        // to avoid loading and parsing the index again
+        g_header = (headerElem.innerHTML).replace("\"local-search-index.js\"", "\"\"");
+
+    }
+
+}
+
+
+function saveTop()
+{
+    topDiv = document.getElementById("top");
+    if (null == topDiv)
+       g_top = "Error, no \"top\" div found. <p>\n";
+    else
+       g_top = topDiv.innerHTML;
+}
+
+
+function saveFooter()
+{
+
+    footerDiv = document.getElementById("doxy-footer");
+
+    if (null == footerDiv)
+        g_footer = "<hr size=\"1\"><address style=\"align: right;\"><small> Error, no \"footer\" <div> found.</small>";
+    else
+        g_footer = footerDiv.innerHTML;
+
+}
+
+
+function writeTop()
+{
+    document.write("<div class\"navigation\" id=\"top\"");
+
+    document.write(g_top);
+
+    document.write("</div>");
+    document.write("<p>");
+}
+
+function writeHeader()
+{
+
+
+    document.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
+    document.write("<html><head>\n");
+
+    document.write(g_header);
+
+    document.write("</head>");
+
+
+
+}
+
+
+function writeFooter(){
+
+     document.write("<div id=\"footer\">\n");
+     document.write(g_footer);
+     document.write("</div>\n");
+
+}
+
+
+function searchForWord( searchWord, statsList)
+{
+
+    hashIndex = computeIndex(searchWord);
+
+
+    indexEntry  = theIndex[hashIndex];
+
+
+    var start = statsList.length;
+    var count = start;
+
+    var totalHi = 0;
+       var totalFreqHi = 0;
+       var totalFreqLo = 0;
+
+
+    if (indexEntry != null)
+    {  //found words matching the hash key
+
+        for (var i = 0; i< indexEntry.length; i++)
+        {
+            foundWord = indexEntry[i];
+            if (null == foundWord)
+                continue;
+            if (  foundWord.indexOf(searchWord) != -1)
+            {
+                //look up the words array for the document list
+                var multiplier = 1;
+
+                var statInfo = new Object();
+                statInfo.word = searchWord;
+                statInfo.match = foundWord;
+                if (foundWord.length == searchWord.length)
+                    multiplier = 2;
+
+                statInfo.docs = words[("#" + foundWord)];
+
+                if (null == statInfo.docs)
+                   continue;
+
+                for (var j = 0; j < statInfo.docs.length; j++)
+                {
+                    var matchingDoc = statInfo.docs[j];
+                    if (matchingDoc == null)
+                    {
+                        //document.write("matchingDoc is NULL <p>");
+                        continue;
+                    }
+
+                   //lsb of freq records whether it is high priority
+                    matchingDoc.hi =  matchingDoc.f&1;
+
+                    matchingDoc.f =  matchingDoc.f>>1;
+                    var freq = matchingDoc.f;
+
+                    matchingDoc.rank = 0.0;
+
+                    if (matchingDoc.hi) // word occurs in high priority doc
+                    {
+                       totalHi++;
+                       totalFreqHi += freq*multiplier;
+                    }
+                    else // word occurs in low priority doc
+                    {
+                        totalFreqLo += freq*multiplier;
+                    }
+
+                    matchingDoc.docName = (urls[matchingDoc.x]).n;
+                    matchingDoc.docUrl = (urls[matchingDoc.x]).u;
+
+                }
+
+                statsList[count++] = statInfo;
+
+            }
+        }
+
+       totalFreq=(totalHi+1)* totalFreqLo + totalFreqHi;
+       for (count = start; count < statsList.length; count++)
+       {
+              statInfo = statsList[count];
+              multiplier = 1;
+              // whole word matches have a double weight
+              if (statInfo.full)
+                   multiplier=2;
+              for (i=0; i < statInfo.docs.length;i++)
+              {
+                    docInfo = statInfo.docs;
+                    // compute frequency rank of the word in each doc
+
+                    if (docInfo[i] == null)
+                        continue;
+
+                    freq = docInfo[i].f;
+                    if (docInfo[i].hi > 0)
+                    {
+                       statInfo.docs[i].rank=
+                         (freq*multiplier+totalFreqLo)/totalFreq;
+                    }
+                    else
+                    {
+                      statInfo.docs[i].rank=
+                           (freq*multiplier)/totalFreq;
+                    }
+             }//for (i=0..
+        }//for (count=...
+    } //if (indexEntry != null)
+
+} //searchForWord
+
+
+
+function report_results(docs, query)
+{
+
+
+  writeHeader();
+  document.write("<body>");
+  writeTop();
+
+  document.write("&nbsp;");
+  document.write("<div class=\"searchResults\">");
+
+  document.write("<table cellspacing=\"2\">\n");
+  document.write("  <tr>\n");
+  document.write("    <td colspan=\"2\"><h2>" + search_results() + "</h2></td>\n");
+  document.write("  </tr>\n");
+
+  var numDocs = 0;
+  for (docsKey in docs)
+     numDocs++;
+
+  if (numDocs==0)
+  {
+    document.write("  <tr>\n");
+    document.write("    <td colspan=\"2\">" + matches_text(0, query) + "</td>\n");
+    document.write("  </tr>\n");
+  }
+  else
+  {
+    document.write("  <tr>\n");
+    document.write("    <td colspan=\"2\">" + matches_text(numDocs, query));
+    document.write("\n");
+    document.write("    </td>\n");
+    document.write("  </tr>\n");
+    num=1;
+    for (var i = 0; i < numDocs; i++)
+    {
+        doc = docs[i];
+        document.write("  <tr>\n");
+        document.write("    <td align=\"right\">" + num + "</td>");
+        document.write(    "<td><a class=\"el\" href=\"" + doc.docUrl  +"\">" + doc.docName + "</a></td>\n");
+        document.write("  <tr>\n");
+        document.write("    <td></td><td class=\"tiny\">" + report_matches() + " ");
+
+        numWords = doc.words.length;
+
+        for (var j =0; j< numWords; j++)
+        {
+          wordInfo = doc.words[j];
+          word = wordInfo.word;
+          matchRight = wordInfo.match.substr(word.length, wordInfo.match.length);
+          document.write("<b>" + word + "</b>" + matchRight +"(" + wordInfo.freq + ") ");
+        }
+        document.write("    </td>\n");
+        document.write("  </tr>\n");
+        num++;
+    }
+  }
+  document.write("</table>\n");
+
+  document.write("</div>"); //contents
+
+  writeFooter();
+
+}
+
+
+
+function compare_rank(a,b)
+{
+      if (a.rank == b.rank)
+      {
+        return 0;
+      }
+      return (a.rank > b.rank) ? -1 : 1;
+}
+
+function sort_results(docs)
+{
+
+  return docs.sort(compare_rank);
+
+}
+
+
+
+
+
+function combine_results(results,docs)
+{
+
+    numResults = results.length;
+
+    keyedDocs = new Array();
+
+    for (var i =0; i< numResults; i++)
+    {
+        wordInfo = results[i];
+        docsList = wordInfo.docs;
+        numDocs = docsList.length;
+        for (var j = 0; j< numDocs; j++)
+        {
+            di = docsList[j];
+            if (di == null)
+                continue;
+            docKey = di.docUrl;
+            rank = di.rank;
+
+            if (keyedDocs[docKey] != null)
+            {
+                keyedDocs[docKey].rank += rank;
+
+            }else
+            {
+                docInfo = new Object();
+                docInfo.docUrl = docKey;
+                docInfo.docName = di.docName;
+                docInfo.rank = rank;
+                docInfo.words = new Array();
+
+                keyedDocs[docKey] = docInfo;
+            }
+
+            wi = new Object();
+            wi.word = wordInfo.word;
+            wi.match = wordInfo.match;
+            wi.freq = di.f;
+
+            idx = keyedDocs[docKey].words.length;
+            keyedDocs[docKey].words[idx] = wi;
+        }
+
+    }
+
+
+    var i = 0;
+    for (docKey in keyedDocs)
+    {
+       // document.write("docKey = " + docKey + "<p>");
+        docs[i] = keyedDocs[docKey];
+        i++;
+    }
+    return docs;
+
+}
+
+
+
+
+function filter_results(docs, requiredWords, forbiddenWords)
+{
+    filteredDocs = new Array();
+    var numPassed = 0;
+
+
+    for (var i = 0; i < docs.length; i++)
+    {
+        copyIt = true;
+        words = docs[i].words;
+
+
+        for (var j = 0; j< requiredWords.length; j++)
+        {
+            reqWord = requiredWords[j];
+            found = false;
+
+            for (var k = 0; k < words.length; k++)
+            {
+                found = (words[k].word == reqWord);
+                if (found)
+                    break;
+            }
+            if (!found)
+            {
+                copyIt = false; // document fails to contain one of the
+                              // required words.
+                break;
+            }
+        }
+
+        if (copyIt)
+        {   //don't bother checking for forbidden words
+            //if it has failed the required words test
+
+            for (var j = 0; j< forbiddenWords.length; j++)
+            {
+                forbiddenWord = forbiddenWords[j];
+                found = false;
+                for (var k = 0; k < words.length; k++)
+                {
+                    found = (words[k].word == forbiddenWord);
+                    if (found)
+                    {
+                        copyIt = false;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (copyIt)
+        {
+            filteredDocs[numPassed] = docs[i];
+            numPassed++;
+        }
+
+    }
+    return filteredDocs;
+
+}
+
+
+
+
+
+function doSearch( theIndex, param)
+{
+
+    saveHeader();
+    saveTop();
+    saveFooter();
+    indexArray = theIndex;
+
+    searchTerms = getParam(param);
+
+
+
+    //indexText =  document.getElementById("index").innerHTML;
+    //window.alert(indexText);
+
+    var statsList = new Array();
+
+    requiredWords = new Array();
+    forbiddenWords = new Array();
+    searchWords   = searchTerms.split("+");
+
+    foundWords = new Array();
+
+    for (var i = 0; i< searchWords.length; i++)
+    {
+        word = unescape(searchWords[i]);
+        word = word.toLowerCase();
+        if (word[0] == '+')
+        {
+            word = word.substr(1);
+            requiredWords[requiredWords.length] = word;
+          //  document.write("required = " + word + "<p>");
+        }
+        if (word[0] == '-')
+        {
+            word = word.substr(1);
+            forbiddenWords[forbiddenWords.length] = word;
+           // document.write("forbidden = " + word + "<p>");
+        }
+
+        if (foundWords[word] == null)
+        {
+            searchForWord( word, statsList);
+            foundWords[word] = i;
+        }
+
+    }
+
+
+    docs = new Array();
+    combine_results(statsList, docs);
+
+    filteredDocs = filter_results(docs, requiredWords, forbiddenWords);
+
+
+
+
+    filteredDocs =  sort_results(filteredDocs);
+
+    report_results(filteredDocs, unescape(searchWords.join(" ")));
+
+
+
+
+}
+
+
+
+function fillSearchBox(param)
+{
+    searchTerms = getParam(param);
+    searchWords   = searchTerms.split("+");
+    searchQuery = searchWords.join(" ");
+
+    queryElement = document.getElementById("query");
+    if (null != queryElement)
+        queryElement.value = unescape(searchQuery);
+    else
+        window.alert("queryElement is null");
+
+}
+
+
+
+

Property changes on: src/local-search.js
___________________________________________________________________
Name: svn:executable
   + *

Index: src/translator_cz.h
===================================================================
--- src/translator_cz.h	(revision 642)
+++ src/translator_cz.h	(working copy)
@@ -77,7 +77,7 @@
 //    something else.  It is difficult to find the general translation
 //    for all kinds in the Czech language.
 
-class TranslatorCzech : public Translator
+class TranslatorCzech : public TranslatorAdapter_1_5_4
 {
   public:
     // --- Language control methods -------------------
Index: src/translator_kr.h
===================================================================
--- src/translator_kr.h	(revision 642)
+++ src/translator_kr.h	(working copy)
@@ -50,7 +50,7 @@
  Translator class (by the local maintainer) when the localized
  translator is made up-to-date again.
 */
-class TranslatorKorean : public Translator
+class TranslatorKorean : public TranslatorAdapter_1_5_4
 {
   protected:
     friend class TranslatorAdapterBase;
Index: src/translator_sr.h
===================================================================
--- src/translator_sr.h	(revision 642)
+++ src/translator_sr.h	(working copy)
@@ -24,7 +24,7 @@
 // UTF-8 patch by Nenad Bulatovic <buletina@gmail.com>
 // translation update by Andrija M. Bosnjakovic <andrija@etf.bg.ac.yu>
 
-class TranslatorSerbian : public Translator
+class TranslatorSerbian : public TranslatorAdapter_1_5_4
 {                                
 private:
    QCString decode(const QCString& sInput)
Index: src/translator_de.h
===================================================================
--- src/translator_de.h	(revision 642)
+++ src/translator_de.h	(working copy)
@@ -120,7 +120,7 @@
 #ifndef TRANSLATOR_DE_H
 #define TRANSLATOR_DE_H
 
-class TranslatorGerman : public Translator
+class TranslatorGerman : public TranslatorAdapter_1_5_4
 {
   public:
 
Index: src/choose-search.js
===================================================================
--- src/choose-search.js	(revision 0)
+++ src/choose-search.js	(revision 0)
@@ -0,0 +1,27 @@
+/*! choose-search.js
+ *
+ * Choose whether to use PHP or JavaScript search.
+ *
+ * @author Mitchell Fraser
+ *
+ */
+
+function usingServer()
+{
+    return (document.URL.indexOf("http") == 0);
+}
+
+
+function chooseSearch()
+{
+    if (usingServer() )
+    {
+        document.searchForm.action = "search.php"
+    }
+    else
+    {
+        document.searchForm.action = "local-search.html"
+    }
+
+    return true;
+}

Property changes on: src/choose-search.js
___________________________________________________________________
Name: svn:executable
   + *

Index: src/translator_sc.h
===================================================================
--- src/translator_sc.h	(revision 642)
+++ src/translator_sc.h	(working copy)
@@ -40,7 +40,7 @@
  Translator class (by the local maintainer) when the localized
  translator is made up-to-date again.
 */
-class TranslatorSerbianCyrilic : public Translator
+class TranslatorSerbianCyrilic : public TranslatorAdapter_1_5_4
 {
   public:
 
Index: src/doxygen.cpp
===================================================================
--- src/doxygen.cpp	(revision 642)
+++ src/doxygen.cpp	(working copy)
@@ -10201,6 +10201,12 @@
     msg("Generating search index\n");
     HtmlGenerator::writeSearchPage();
     Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search.idx");
+
+     if (Config_getBool("LOCALSEARCH"))
+     {
+       HtmlGenerator::writeLocalSearchPages();
+       Doxygen::searchIndex->writeJavaScriptIndex(Config_getString("HTML_OUTPUT")+"/local-search-index.js");
+     }
   }
   if (Debug::isFlagSet(Debug::Time))
   {
Index: src/config.l
===================================================================
--- src/config.l	(revision 642)
+++ src/config.l	(working copy)
@@ -3177,6 +3177,18 @@
                     "used. If set to NO the values of all tags below this one will be ignored. \n",
                     FALSE
                  );
+   cb = addBool(
+                    "LOCALSEARCH",
+                    "The LOCALSEARCH tag specifies whether or not Doxygen should \n"
+                    "produce a search engine capable of searching the HTML output without an HTTP server.\n"
+                    "It will use Javascript to allow searching for keywords using a normal browser."
+                    "If set to NO, search will only be possible if the environment can run PHP scripts,"
+                    "which is typical of pages served from HTTP web sites, but not locally stored files."
+                    "To use LOCALSEARCH, SEARCHENGINE must be set to YES.",
+                    TRUE
+                 );
+   cb->addDependency("SEARCHENGINE");
+
   addObsolete("CGI_NAME");
   addObsolete("CGI_URL");
   addObsolete("DOC_URL");
@@ -3205,7 +3217,7 @@
       while ((size=f.readBlock(contents.data()+totalSize,bSize))==bSize)
       {
         totalSize+=bSize;
-        contents.resize(totalSize+bSize); 
+        contents.resize(totalSize+bSize);
       }
       totalSize+=size+2;
       contents.resize(totalSize);
Index: src/translator_ru.h
===================================================================
--- src/translator_ru.h	(revision 642)
+++ src/translator_ru.h	(working copy)
@@ -26,7 +26,7 @@
 #ifndef TRANSLATOR_RU_H
 #define TRANSLATOR_RU_H
 
-class TranslatorRussian : public Translator
+class TranslatorRussian : public TranslatorAdapter_1_5_4
 {
   public:
     /*! Used for identification of the language. */
Index: src/searchindex.cpp
===================================================================
--- src/searchindex.cpp	(revision 642)
+++ src/searchindex.cpp	(working copy)
@@ -20,6 +20,7 @@
 #include "config.h"
 #include <qfile.h>
 #include <ctype.h>
+#include <qregexp.h>
 
 
 // file format: (all multi-byte values are stored in big endian format)
@@ -136,6 +137,78 @@
   f.putch(0);
 }
 
+
+static QCString escape(const QCString &input)
+{
+    QCString output(input);
+    output =  output.replace(QRegExp("\\"), "\\\\"); // '\' -> '\\'
+    return output.replace(QRegExp("\""), "\\\""); // '"' -> '\"'
+}
+
+void SearchIndex::writeJavaScriptIndex(const char *fileName)
+{
+    int i;
+    QFile f(fileName);
+    if (f.open(IO_WriteOnly))
+    {
+        QTextStream stream( &f );
+        for (i=0; i < numIndexEntries; i++)
+        {
+            QList<IndexWord> *wlist = m_index[i];
+            if (!wlist->isEmpty())
+            {
+                 stream << "x[" << i << "] = [";
+                 QListIterator<IndexWord> iwi(*wlist);
+                 IndexWord *iw;
+                 for (iwi.toFirst();(iw=iwi.current());++iwi)
+                 {
+                     stream << "\"" << escape(iw->word()) << "\"";
+                     stream << ",";
+                 }
+                 stream << "];";
+                 stream << "\n";
+            }
+        }
+
+        QDictIterator<IndexWord> wordIter(m_words);
+        IndexWord *word;
+
+        for (wordIter.toFirst(); (word=wordIter.current());++wordIter)
+        {
+            stream <<"w[\"#" << escape(word->word()) << "\"] = ";
+            QIntDictIterator<URLInfo> urlIter = word->urls();
+            URLInfo *url;
+
+            stream << "[";
+            for (urlIter.toFirst(); (url=urlIter.current()); ++urlIter)
+            {
+               stream << "{x: " << url->urlIdx << "," << "f:" << url->freq << "},";
+
+
+            }
+            stream << "];\n";
+
+
+
+        }
+
+
+
+
+        QIntDictIterator<URL> udi(m_urls);
+        URL *url;
+        int urlIdx = 0;
+        for (udi.toFirst();(url=udi.current());++udi)
+        {
+            stream << "u[" << udi.currentKey() << "] = { n: \"" << url->name << "\", u: \"" << url->url << "\"};\n";
+            urlIdx++;
+        }
+
+    }
+}
+
+
+
 void SearchIndex::write(const char *fileName)
 {
   int i;
Index: src/htmlgen.cpp
===================================================================
--- src/htmlgen.cpp	(revision 642)
+++ src/htmlgen.cpp	(working copy)
@@ -51,6 +51,27 @@
 #include "search_php.h"
 ;
 
+static const char local_search_globals[]=
+#include "local-search-globals_js.h"
+;
+
+static const char choose_search[]=
+#include "choose-search_js.h"
+;
+
+
+static const char local_search_script[]=
+#include "local-search_js.h"
+;
+
+
+static const char  locals_search_script_elements[] =
+    "<script type=\"text/javascript\" src=\"choose-search.js\"></script>\n"
+    "<script type=\"text/javascript\" src=\"local-search-globals.js\"></script>"
+    "<script  type=\"text/javascript\" src=\"local-search-index.js\"></script>"
+    "<script type=\"text/javascript\" src=\"local-search.js\"></script>\n";
+
+
 static QCString g_header;
 static QCString g_footer;
 
@@ -542,6 +563,9 @@
   if (!Config_getString("HTML_FOOTER").isEmpty()) 
   {
     g_footer=fileToString(Config_getString("HTML_FOOTER"));
+
+    //to close off the the <div id="doxy-footer">
+    g_footer=substitute(g_footer, "</body","</div></body");
     //printf("g_footer='%s'\n",g_footer.data());
   }
   createSubDirs(d);
@@ -558,8 +582,21 @@
   t << defaultStyleSheet;
 }
 
+
+
+static void writeJsSearchIncludes(QTextStream &t)
+{
+
+  t << "<script type=\"text/javascript\" src=\"choose-search.js\"></script>";
+
+}
+
+
+
+
 static void writeDefaultHeaderFile(QTextStream &t, const char *title,
-                                   const char *relPath,bool usePathCmd)
+                                   const char *relPath,bool usePathCmd,
+                                   bool forLocalSearch)
 {
   QString relPathStr;
   if (usePathCmd) 
@@ -594,7 +631,17 @@
   
   t << "\" rel=\"stylesheet\" type=\"text/css\">\n";
   t << "<link href=\"" << relPathStr << "tabs.css\" rel=\"stylesheet\" type=\"text/css\">\n";
-  t << "</head><body>\n";
+
+  if (forLocalSearch)
+  {
+    t << locals_search_script_elements;
+    t << "</head>\n";
+    t << "<body onLoad=\"fillSearchBox('query');return doSearch(theIndex,  'query');\">\n";
+  }
+  else
+  {
+    t << "</head><body>\n";
+  }
 }
 
 
@@ -602,7 +649,7 @@
 {
   QTextStream t(&file);
   t.setEncoding(QTextStream::UnicodeUTF8);
-  writeDefaultHeaderFile(t,"$title",relativePathToRoot(0),TRUE);
+  writeDefaultHeaderFile(t,"$title",relativePathToRoot(0),TRUE, FALSE);
 }
 
 void HtmlGenerator::writeFooterFile(QFile &file)
@@ -698,22 +745,30 @@
   lastFile = fileName;
   if (g_header.isEmpty()) 
   {
-    writeDefaultHeaderFile(t,dispTitle,relPath,FALSE);
+    writeDefaultHeaderFile(t,dispTitle,relPath,FALSE, FALSE);
   }
   else
   {
     t << substituteKeywords(g_header,convertToHtml(dispTitle),relPath);
   }
-  t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen " 
+  t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
     << versionString << " -->" << endl;
+
+  if (Config_getBool("SEARCHENGINE") &&
+      Config_getBool("LOCALSEARCH"))
+    writeJsSearchIncludes(t);
+
   generateDynamicSections(t,relPath);
 }
 
 static void writePageFooter(QTextStream &t,const QCString &lastTitle,
                             const QCString relPath)
 {
+
+  t << "<div id=\"doxy-footer\">\n";
   if (g_footer.isEmpty())
   {
+
     t << "<hr size=\"1\"><address style=\"text-align: right;\"><small>";
     t << theTranslator->trGeneratedAt(
         dateToString(TRUE),
@@ -733,12 +788,14 @@
            "src=\"http://jigsaw.w3.org/css-validator/images/vcss\" "
            "alt=\"This page uses valid CSS!\"></a></p>";
     }
+    t << "</div>\n";
     t << "\n</body>\n</html>\n";
   }
   else
   {
     t << substituteKeywords(g_footer,convertToHtml(lastTitle),relPath);
   }
+
 }
 
 void HtmlGenerator::writeFooter()
@@ -2000,13 +2057,18 @@
     QCString searchFor = fixSpaces(theTranslator->trSearchForIndex());
     if (searchFor.at(0)=='S') searchFor="<u>S</u>"+searchFor.mid(1);
     t << "    <li>\n";
-    t << "      <form action=\"" << relPath << "search.php\" method=\"get\">\n";
+    t << "      <form action=\"" << relPath << "search.php\" method=\"get\"";
+
+    if (Config_getBool("LOCALSEARCH"))
+        t << " name=\"searchForm\" onSubmit=\"return chooseSearch('query');\" ";
+
+    t << ">\n";
     t << "        <table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n";
     t << "          <tr>\n";
     t << "            <td><label>&nbsp;" << searchFor << "&nbsp;</label></td>\n";
     if (hli!=HLI_Search)
     {
-      t << "            <td><input type=\"text\" name=\"query\" value=\"\" size=\"20\" accesskey=\"s\"/></td>\n";
+      t << "            <td><input id=\"query\" type=\"text\" name=\"query\" value=\"\" size=\"20\" accesskey=\"s\"/></td>\n";
       t << "          </tr>\n";
       t << "        </table>\n";
       t << "      </form>\n";
@@ -2079,6 +2141,127 @@
   writeDefaultQuickLinks(t,compact,hli,relPath);
 }
 
+
+static void writeFile(QCString fileName, const char contents[])
+{
+  QCString fullPath = Config_getString("HTML_OUTPUT") + "/" + fileName;
+
+  QFile f(fullPath);
+  if (f.open(IO_WriteOnly))
+  {
+    QTextStream t(&f);
+    t << contents;
+  }
+}
+
+static void writeFileAndTranslationFns(QCString fileName, const char contents[])
+{
+  QCString fullPath = Config_getString("HTML_OUTPUT") + "/" + fileName;
+
+  QFile f(fullPath);
+  if (f.open(IO_WriteOnly))
+  {
+    QTextStream t(&f);
+    t << contents;
+    t << "\n";
+    t << "function search_results()\n";
+    t << "{\n";
+    t << "  return \"" << theTranslator->trSearchResultsTitle() << "\";\n";
+    t << "}\n";
+    t << "\n";
+    t << "function matches_text(num,query)\n";
+    t << "{\n";
+    t << "  if (num==0)\n";
+    t << "  {\n";
+    t << "    return \"" << theTranslator->trLocalSearchResults(0) << "\";\n";
+    t << "  }\n";
+    t << "  else if (num==1)\n";
+    t << "  {\n";
+    t << "    return \"" << theTranslator->trLocalSearchResults(1) << "\";\n";
+    t << "  }\n";
+    t << "  else // num>1\n";
+    t << "  {\n";
+    t << "    return \"" << theTranslator->trLocalSearchResults(2) << "\";\n";
+    t << "  }\n";
+    t << "}\n";
+    t << "\n";
+    t << "function report_matches()\n";
+    t << "{\n";
+    t << "  return \"" << theTranslator->trSearchMatches() << "\";\n";
+    t << "}\n";
+    t << "\n";
+    t << "\n";
+
+  }
+}
+
+
+void HtmlGenerator::writeLocalSearchPages()
+{
+  if (Config_getBool("SEARCHENGINE") &&
+      Config_getBool("LOCALSEARCH") &&
+      Config_getBool("GENERATE_HTML"))
+  {
+
+    writeFileAndTranslationFns("local-search-globals.js", local_search_globals);
+    writeFile("local-search.js", local_search_script);
+    writeFile("choose-search.js",choose_search);
+
+
+    QCString fileName =  Config_getString("HTML_OUTPUT") + "/local-search.html";
+    QFile f(fileName);
+    if (f.open(IO_WriteOnly))
+    {
+       QTextStream t(&f);
+       if (g_header.isEmpty())
+       {
+           writeDefaultHeaderFile(t,theTranslator->trSearch().data(),0,FALSE, TRUE);
+       }
+       else
+       {
+           QCString searchHeader = substitute(g_header, "<body",
+                "<body onLoad=\"fillSearchBox('query');return doSearch(theIndex,  'query');\"");
+
+           QCString scriptElems = locals_search_script_elements;
+           scriptElems.append("</head");
+
+           searchHeader = substitute(searchHeader, "</head", scriptElems );
+
+
+           t << substituteKeywords(searchHeader,"Search","");
+       }
+
+      t << "<div class=\"navigation\" id=\"top\">\n";
+      t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
+      << versionString << " -->" << endl;
+
+      if (!Config_getBool("DISABLE_INDEX"))
+      {
+        writeDefaultQuickLinks(t,TRUE,HLI_Search,"");
+      }
+      else
+      {
+        t << "&nbsp;\n<div class=\"qindex\">\n";
+        t << " <form class=\"search\" action=\"search.php\" method=\"get\"";
+        t << " name=\"searchForm\" onSubmit=\"return chooseSearch('query');\" ";
+        t << " >\n";
+      }
+      t << " <td><input id=\"query\" type=\"text\" name=\"query\" value=\"\" size=\"20\" accesskey=\"s\"/></td>\n";
+      t << "          </tr>\n";
+      t << "        </table>\n";
+      t << "      </form>\n";
+      t << "    </li>\n";
+      t << "  </ul>\n";
+      t << "</div>\n";
+      t << "</div>\n";
+
+      writePageFooter(t,"Search","");
+    }
+
+  }
+}
+
+
 void HtmlGenerator::writeSearchPage()
 {
   if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTML"))
@@ -2091,16 +2274,16 @@
       t.setEncoding(QTextStream::UnicodeUTF8);
       if (g_header.isEmpty()) 
       {
-        writeDefaultHeaderFile(t,theTranslator->trSearch().data(),0,FALSE);
+        writeDefaultHeaderFile(t,theTranslator->trSearch().data(),0,FALSE, FALSE);
       }
       else
       {
         t << substituteKeywords(g_header,"Search","");
       }
-      t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen " 
+      t << "<!-- " << theTranslator->trGeneratedBy() << " Doxygen "
         << versionString << " -->" << endl;
-      if (!Config_getBool("DISABLE_INDEX")) 
-      { 
+      if (!Config_getBool("DISABLE_INDEX"))
+      {
         writeDefaultQuickLinks(t,TRUE,HLI_Search,"");
       }
       else
@@ -2110,7 +2293,29 @@
           << "method=\"get\">\n";
       }
 
+
+
       t << "\n<?php\n\n";
+
+       //output a PHP comment that will appear if the user
+       //tries to search when accessing the files directly
+      t << "#  </tr>    \n";
+      t << "#  </table> \n";
+      t << "#  </form>  \n";
+      t << "#  </ul>    \n";
+      t << "#  </div>   \n";
+      t << "#  <p>    \n";
+      t << "# <h2> " << theTranslator->trUseWebServer() <<  "</h2> \n";
+      t << "# <h3> " << theTranslator->trDefineLocalSearch() << " </h3>\n";
+      t << "#    <p>\n";
+
+
+      //put the PHP code in an HTML comment, so it doesn't
+      // appear to a user who has tried to search when accessing
+      // the files directly
+      t << "# <!-- \n";
+
+
       t << "function search_results()\n";
       t << "{\n";
       t << "  return \"" << theTranslator->trSearchResultsTitle() << "\";\n";
@@ -2138,8 +2343,8 @@
       t << "}\n";
       t << "function end_form($value)\n";
       t << "{\n";
-      t << "  echo \"" 
-        << "            <td><input type=\\\"text\\\" name=\\\"query\\\" value=\\\"$value\\\" size=\\\"20\\\" accesskey=\\\"s\\\"/></td>\\n"
+      t << "  echo \""
+        << "            <td><input id=\\\"query\\\"  type=\\\"text\\\" name=\\\"query\\\" value=\\\"$value\\\" size=\\\"20\\\" accesskey=\\\"s\\\"/></td>\\n"
         << "          </tr>\\n"
         << "        </table>\\n"
         << "      </form>\\n"
@@ -2151,12 +2356,14 @@
       t << "\n";
       t << search_script;
       t << "\n";
+      t << "# -->"; //end the HTML comment that hides the PHP source;
       t << "?>\n";
       writePageFooter(t,"Search","");
     }
   }
 }
 
+
 void HtmlGenerator::generateSectionImages()
 {
   {
Index: src/local-search-globals.js
===================================================================
--- src/local-search-globals.js	(revision 0)
+++ src/local-search-globals.js	(revision 0)
@@ -0,0 +1,18 @@
+﻿
+/*! local-search-globals.js
+ *
+ * Globals variables used in local search of doxygen HTML output.
+ *
+ * @author Mitchell Fraser
+ *
+ */
+
+
+//the hash table
+var x = new Array();
+
+//the urls
+var u = new Array();
+
+//the words
+var w = new Array();
\ No newline at end of file

Property changes on: src/local-search-globals.js
___________________________________________________________________
Name: svn:executable
   + *

Index: src/translator_br.h
===================================================================
--- src/translator_br.h	(revision 642)
+++ src/translator_br.h	(working copy)
@@ -32,7 +32,7 @@
 #ifndef TRANSLATOR_BR_H
 #define TRANSLATOR_BR_H
 
-class TranslatorBrazilian : public Translator
+class TranslatorBrazilian : public TranslatorAdapter_1_5_4
 {
   public:
 
Index: src/translator_nl.h
===================================================================
--- src/translator_nl.h	(revision 642)
+++ src/translator_nl.h	(working copy)
@@ -18,7 +18,7 @@
 #ifndef TRANSLATOR_NL_H
 #define TRANSLATOR_NL_H
 
-class TranslatorDutch : public Translator
+class TranslatorDutch : public TranslatorAdapter_1_5_4
 {
   public:
     QCString idLanguage()
Index: src/translator_adapter.h
===================================================================
--- src/translator_adapter.h	(revision 642)
+++ src/translator_adapter.h	(working copy)
@@ -115,6 +115,15 @@
 
     virtual QCString trTypeConstraints()
     { return english.trTypeConstraints(); }
+
+    virtual QCString trDefineLocalSearch()
+    { return english.trDefineLocalSearch(); }
+
+    virtual QCString trUseWebServer()
+    {  return english.trUseWebServer(); }
+
+    virtual QCString trLocalSearchResults(int numDocuments)
+    { return english.trLocalSearchResults(numDocuments); }
 };
 
 class TranslatorAdapter_1_4_6 : public TranslatorAdapter_1_5_4
Index: src/htmlgen.h
===================================================================
--- src/htmlgen.h	(revision 642)
+++ src/htmlgen.h	(working copy)
@@ -240,6 +240,7 @@
     { t << "<a name=\"" << anchor << "\"></a>"; }
     void linkableSymbol(int,const char *,Definition *,Definition *) {}
 
+    static void writeLocalSearchPages();
     static void writeSearchPage();
     static void generateSectionImages();
 
Index: src/translator_tw.h
===================================================================
--- src/translator_tw.h	(revision 642)
+++ src/translator_tw.h	(working copy)
@@ -41,7 +41,7 @@
 // Translator class (by the local maintainer) when the localized
 // translator is made up-to-date again.
 
-class TranslatorChinesetraditional : public Translator
+class TranslatorChinesetraditional : public TranslatorAdapter_1_5_4
 {
   public:
 
Index: src/translator_en.h
===================================================================
--- src/translator_en.h	(revision 642)
+++ src/translator_en.h	(working copy)
@@ -1774,7 +1774,42 @@
     {
       return "Type Constraints";
     }
+    
+    
+    virtual QCString trLocalSearchResults(int numDocuments)
+    {
+      if (numDocuments==0)
+      {
+        return "Sorry, no documents matching \\\"<b>\" + query + \"</b>\\\".";
+      }
+      else if (numDocuments==1)
+      {
+        return "Found <b>1</b> document matching \\\"<b>\" + query + \"</b>\\\".";
+      }
+      else
+      {
+        return "Found <b>\" + num +  \"</b> documents matching \\\"<b>\" + query + \"</b>\\\". "
+               "Showing best matches first.";
+      }
+    }
+    
+   /*! Error message comment in the search.php visible when the user tries
+    *  to search when accessing the files directly from the filesystem.
+    */
+   virtual QCString trUseWebServer()
+   {
+       return "You must access these documents from a Web server to use search.";
+   }
 
+   /*! Advice on how to make search work when accessing the HTML output directly
+    *  from the filesystem.
+    */
+   virtual QCString trDefineLocalSearch()
+   {
+      return "To search without a Web server, please define \"LOCALSEARCH = Yes\" in the Doxyfile used to create this documentation.";
+   }
+
+
 };
 
 #endif
Index: src/translator_it.h
===================================================================
--- src/translator_it.h	(revision 642)
+++ src/translator_it.h	(working copy)
@@ -80,7 +80,7 @@
 #ifndef TRANSLATOR_IT_H
 #define TRANSLATOR_IT_H
 
-class TranslatorItalian : public Translator
+class TranslatorItalian : public TranslatorAdapter_1_5_4
 {
   public:
 
