gnucash-htdocs beta: Multiple changes pushed

John Ralls jralls at code.gnucash.org
Sun Jun 29 23:07:56 EDT 2025


  discards  https://github.com/Gnucash/gnucash-htdocs/commit/ae40650f (commit)
Updated	 via  https://github.com/Gnucash/gnucash-htdocs/commit/7fa7c4d1 (commit)
	 via  https://github.com/Gnucash/gnucash-htdocs/commit/e111e9f4 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (https://github.com/Gnucash/gnucash-htdocs/commit/ae40650f)
            \
             N -- N -- N (https://github.com/Gnucash/gnucash-htdocs/commit/7fa7c4d1)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.



commit 7fa7c4d139162cea9564911f3ff4e0650b169341
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Jun 29 19:48:19 2025 -0700

    Announce release of GnuCash 5.12

diff --git a/externals/global_params.php b/externals/global_params.php
index aea65e9..be3f81e 100644
--- a/externals/global_params.php
+++ b/externals/global_params.php
@@ -6,15 +6,15 @@
      $major_stable              ="5";
      // TODO: on major_stable 5 in download.phtml copy from $old_stable into the historical
      // section: last_win7 and $last_mac_sierra
-     $minor_stable              ="11";
+     $minor_stable              ="12";
      // Number of Translations: Did we add or dropped some?
      define("PROG_TRANSLATIONS", 61);
 
      $latest_stable             = $major_stable.".".$minor_stable;
      $latest_stable_win         = $latest_stable;
      //$latest_stable_win         = $latest_stable."-1";
-     $latest_stable_mac_arm   = $latest_stable."-2";
-     $latest_stable_mac_x86   = $latest_stable."-2";
+     $latest_stable_mac_arm   = $latest_stable."-1";
+     $latest_stable_mac_x86   = $latest_stable."-1";
 // Change this when there has been a re-tag to add the re-tag letter,
 // e.g. if one retagged 2.6.13 to 2.6.13a, make $tarball = $latest_stable."a".
      $tarball                   = $latest_stable."";
diff --git a/news/250629-5.12.news b/news/250629-5.12.news
new file mode 100644
index 0000000..1bc4793
--- /dev/null
+++ b/news/250629-5.12.news
@@ -0,0 +1,127 @@
+<b>Announcement:</b> GnuCash 5.12 Released
+2025-06-29
+
+<h2>GnuCash 5.12 Released</h2>
+
+<p>The GnuCash development team announces GnuCash 5.12, the thirteenth release in the stable 5.x series.</p>
+
+<h4>Between 5.11 and 5.12, the following bugfixes were accomplished:</h4>
+<ul>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=648768">Bug 648768 - Warning "Change Reconciled Split" has wrong cursor focus</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=797766">Bug 797766 - Automatic decimal point doesn't work properly with zeros when entering stocks.</a><p> Preserve the decimal point when printing numbers with no decimal places to stop the auto-decimal code from triggering when exiting the field. </p></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799490">Bug 799490 - Error on start or opening a gnucash file: Can't parse the URL</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799506">Bug 799506 - reconcile bad date pops to 1969</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799521">Bug 799521 - Segmentation fault on Autocomplete of Description with ß</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799572">Bug 799572 - Return proper status code when Finance::Quote errors during price quote retrieval via CLI. </li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799580">Bug 799580 - Swiss currency symbol is displayed as SFr. instead of CHF</a><p>Replace SFr. with Fr. as SFr. is obsolete but Fr. is still widely used. This is the local symbol so users who want CHF can set it in the security editor. </p></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799582">Bug 799582 - Mortgage and Loan Assistant - Compounding Formula</a><p>Adds a semi-annual compounding period for Canadians and implements the more correct simple-rate formula provided by a Canadian licensed accountant. Also adds support for day-interval loan payments, ensures that the formula on the repayment page reflects changes on that page, ensures that the number and amounts of payments are correct when payments are more frequent than monthly, use the correct intest rate for compunding calculations, and fixes some memory issues.</p></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799590">Bug 799590 - Pressing enter after changing date on initial reconcile information window does not change ending balance.</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799592">Bug 799592 - "No transactions found" when importing CSV transactions</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799593">Bug 799593 - macOS: mariadb hardcodes plugin paths to original install directory.</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799594">Bug 799594 - GnuCash 5.11 fails to build with boost 1.88</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799597">Bug 799597 - Crash when deleting all splits in General Journal</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799602">Bug 799602 - Unit Price on Invoice will NOT display as decimals</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799603">Bug 799603 - Does not save to mysql on localhost.</a></li>
+    <li><a href="https://bugs.gnucash.org/show_bug.cgi?id=799623">Bug 799623 - test-backend-dbi fails after 2038</a></li>
+</ul>
+
+<h4>The following fixes and improvements were not associated with bug reports:</h4>
+<ul>
+    <li>[reports]Lazily generate sub-reports. Reports with links to detail sub-reports like the budget reports would take a long time to generate because they built both the main report and all of the sub-reports. Now the sub-reports generate when the user clicks the link in the main report.</li>
+    <li>Security editor quote sources: Add new source, China Merchants Bank. Remove no longer supported F::Q Modules Bloomberg.pm, DWSFunds, Investor's Exchange (U.S.), Morningstar Australia, Skanddinaviska Enskilda Banken, Tiaacref.pm, Troweprice.pm and many of the multi-source sources from the Security Editor.</li>
+    <li>[import-main-matcher.cpp] Add tooltips to transaction A, U+C, and C action columns in the generic transaction import matcher. </li>
+    <li>[reports] Use ICU for Unicode string comparison and substring search because it knows how to correctly localize comparisons of accented and unaccented characters.</li>
+    <li>[reports] more robust error handling if target report doesn't exist.</li>
+    <li>Register: Ensure splits belong to transaction when doing bulk operations on a transaction's splits.</li>
+    <li>Drop the definition of __EXTENSIONS__ from three files and instead move it to compiler options if on a platform that needs it.</li>
+    <li>Avoid non-POSIX "echo -n" behavior in util/gnc-vcs-info.</li>
+    <li>Add testbuild target which builds tests without running them to accommodate packaging processes that run ctest separately.</li>
+    <li>[engine.i] convert gnc_account_accumulate_at_dates to c++.</li>
+    <li>[gnc-engine-guile.cpp] helper gnc_split_to_scm function.</li>
+    <li>[gnc-engine-guile] reduce overhead of gnc_foo_to_scm by caching the result of SWIG_TypeQuery(typestr) </li>
+    <li>[balance-forecast] optimise some loops: fewer temporary lists and gc </li>
+    <li>Let cmake probe for the existence of HAVE_STRUCT_TM_GMTOFF, fix build of test-gnc-date on systems without HAVE_STRUCT_TM_GMTOFF, and avoid unused variable warnings on systems without HAVE_STRUCT_TM_GMTOFF</li>
+    <li>Wrap include of gtest.h and gmock.h with a warning-silencing pragma. See https://github.com/google/googletest/issues/4701 The warnings cause the Arch Linux CI to fail because of -Werror. </li>
+    <li>Fixed GetInvoiceFromTxn to convert to the right type of Python object for a GncInvoice.</li>
+    <li>[test-report-utilities] more tests for gnc:account-accumulate-at-dates testing balances at date boundaries </li>
+</ul>
+<p>New and Updated Translations: Arabic, Bulgarian, Chinese (Simplified Han script), Danish, Dutch, Finnish, French, German, Hungarian, Portuguese, Romanian, Russian, Spanish, Swedish, Turkish</p>
+
+
+<a href="https://hosted.weblate.org/engage/gnucash/">Help translate GnuCash on Weblate</a>
+
+<h4>Known Problems</h4>
+<p><a href="https://bugs.gnucash.org/buglist.cgi?bug_severity=blocker&bug_severity=critical&bug_severity=major&bug_severity=normal&bug_severity=minor&bug_severity=trivial&bug_status=NEW&bug_status=ASSIGNED&bug_status=NEEDINFO&bug_status=REOPENED&limit=0&list_id=8149&order=priority%2Cbug_severity&query_format=advanced">Complete list of all open bugs.</a></p>
+
+<h2>Documentation</h2>
+<h4>The following fixes and improvements were not associated with bug reports:</h4>
+<ul>
+    <li>German translation: Fix some typos</li>
+    <li>German translation: Remove the Finance::Quote appendix. The content has been moved to the wiki.</li>
+</ul>
+
+<p>Updated Translations: German.</p>
+
+<h3>Getting GnuCash for Windows and MacOS</h3>
+<p>GnuCash is provided for both Microsoft Windows 10® and later
+    and MacOS 10.13 (High Sierra)® and later in pre-built, all-in-one
+    packages. An installer is provided for Microsoft Windows® while
+    the MacOS® package is a disk image containing a drag-and-drop
+    application bundle.</p>
+
+<p>GnuCash is also available as a flatpak from Flathub.org. <a href="https://wiki.gnucash.org/wiki/Flatpak">Instructions for installing and running.</a></p>
+
+<p>The SHA256 Hashes for the downloadable files are:</p>
+<ul>
+    <li><code>b35b4756be12bcfdbed54468f30443fa53f238520a9cead5bde2e6c4773fbf39</code>  gnucash-5.12.tar.bz2</li>
+    <li><code>fa279ac0378b1860ede15a8b6645628e17e7e94df496d69be8fd5d20a570ccc7</code>  gnucash-5.12.tar.gz</li>
+    <li><code>55e03a7161d9dc34309a453b85d0e16f1e58f4b7f7b4b2b17aa8be03d538f863</code>  gnucash-5.12.setup.exe</li>
+    <li><code>a1f7454d07bfb536e641ccf9423b51f00dbd2374d8097d5ac5b918159832cc37</code>  Gnucash-Arm-5.12-1.dmg</li>
+    <li><code>090d197df67926823360ee8bfaacffa60c10f467036080fd2a83f9f96bdebc40</code>  Gnucash-Intel-5.12-1.dmg</li>
+    <li><code>c2a67aef439f25b8e3d43cf5cc29756fae0e82e252f0abf059b35663594ea994</code>  gnucash-docs-5.12.tar.gz</li>
+</ul>
+
+<ul>
+    <li>SourceForge:
+        <ul>
+            <li><a href="https://downloads.sourceforge.net/gnucash/gnucash%20%28stable%29/5.12/gnucash-5.12.setup.exe">Win32</a></li>
+            <li><a href="https://downloads.sourceforge.net/gnucash/gnucash%20%28stable%29/5.12/Gnucash-Arm-5.12-1.dmg">Mac-Apple Silicon</a></li>
+            <li><a href="https://downloads.sourceforge.net/gnucash/gnucash%20%28stable%29/5.12/Gnucash-Intel-5.12-1.dmg">Mac-Intel</a></li>
+        </ul></li>
+    <li>Github
+        <ul>
+            <li><a href="https://github.com/Gnucash/gnucash/releases/download/5.12/gnucash-5..setup.exe">Win32</a></li>
+            <li><a href="https://github.com/Gnucash/gnucash/releases/download/5.12/Gnucash-Arm-5.12-1.dmg">Mac-Apple Silicon</a></li>
+            <li><a href="https://github.com/Gnucash/gnucash/releases/download/5.12/Gnucash-Intel-5.12-1.dmg">Mac-Intel</a></li>
+        </ul></li></ul>
+
+<h3>Getting GnuCash as source code</h3>
+<p>If you want to compile GnuCash 5.12 for yourself, the source code can be downloaded from:</p>
+<ul>
+
+    <li>Sourceforge: <a href="https://downloads.sourceforge.net/gnucash/gnucash%20%28stable%29/5.12/gnucash-5.12.tar.bz2">bzip2</a>, <a href="https://downloads.sourceforge.net/gnucash/gnucash%20%28stable%29/5.12/gnucash-5.12.tar.gz">gzip</a>.</li>
+
+    <li>Github: <a href="https://github.com/Gnucash/gnucash/releases/download/5.12/gnucash-5.12.tar.bz2">bzip</a>, <a href="https://github.com/Gnucash/gnucash/releases/download/5.12/gnucash-5.12.tar.gz">gzip</a></li>
+
+    <li>You can also checkout the sources directly from the git repository as <a href="https://wiki.gnucash.org/wiki/Git">described here.</a></li>
+</ul>
+
+<p>To compile GnuCash from the source code by yourself, you will need at least <a href="https://www.gtk.org">Gtk+</a> 3.22.30, <a href="https://www.gnu.org/software/guile/">Guile</a> 2.0.9, <a href="https://www.boost.org/">Boost</a> 1.67, <a href="https://webkitgtk.org/">WebKitGtk</a> 2.4, <a href="https://github.com/google/googletest">GoogleTest</a> 1.8.0, <a href="https://cmake.org/">cmake 3.14.5</a> and <a href="http://www.swig.org/">SWIG</a> 3.0.12. Please consult the README.dependencies file in the sources for the exact list of dependencies and versions.</p>
+
+<h3>Getting the documentation</h3>
+
+<p>The documentation is available at <a href="https://www.gnucash.org/docs.phtml">Documentation page</a> of the <a href="https://www.gnucash.org/">GnuCash website</a>. The 5.12 documentation can be found under "GnuCash v5 (current stable release)" in multiple languages both for reading online and for download in pdf, epub, and mobi formats. The documentation is also included in the MacOS and Windows application bundles.</p>
+
+<p>If you want to compile the GnuCash Documentation 5.12 for yourself, the source code can be downloaded from:</p>
+<ul>
+    <li><a href="https://downloads.sourceforge.net/gnucash/gnucash%20%28stable%29/5.12/gnucash-docs-5.12.tar.gz">Sourceforge</a> or <a href="https://github.com/Gnucash/gnucash/releases/download/5.12/gnucash-docs-5.11.tar.gz">GitHub</a></li>
+    <li>You can also checkout the sources directly from the git repository as <a href="https://wiki.gnucash.org/wiki/Git">described here.</a></li>
+</ul>
+
+
+<h3>About the Program</h3>
+
+<p>GnuCash is a free, open source accounting program released under
+    the GNU General Public License (GPL) and available for GNU/Linux,
+    *BSD, Solaris, MacOS, and Microsoft Windows.  Programming on GnuCash
+    began in 1997, and its first stable release was in 1998.</p>

commit e111e9f4f36bf0393d650ae15fe6fa58cef28a98
Author: John Ralls <jralls at ceridwen.us>
Date:   Sun Jun 29 20:07:20 2025 -0700

    Use the php gettext module instead of an ancient copy.

diff --git a/accept-to-gettext.inc b/accept-to-gettext.inc
deleted file mode 100644
index 6f366d0..0000000
--- a/accept-to-gettext.inc
+++ /dev/null
@@ -1,184 +0,0 @@
-<?php
-/*
- * accept-to-gettext.inc -- convert information in 'Accept-*' headers to
- * gettext language identifiers.
- * Copyright (c) 2003, Wouter Verhelst <wouter at debian.org>
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Usage:
- *
- *  $locale=al2gt(<array of supported languages/charsets in gettext syntax>,
- *                <MIME type of document>);
- *  setlocale('LC_ALL', $locale); // or 'LC_MESSAGES', or whatever...
- *
- * Example:
- *
- *  $langs=array('nl_BE.ISO-8859-15','nl_BE.UTF-8','en_US.UTF-8','en_GB.UTF-8');
- *  $locale=al2gt($langs, 'text/html');
- *  setlocale('LC_ALL', $locale);
- *
- * Note that this will send out header information (to be
- * RFC2616-compliant), so it must be called before anything is sent to
- * the user.
- * 
- * Assumptions made:
- * * Charset encodings are written the same way as the Accept-Charset
- *   HTTP header specifies them (RFC2616), except that they're parsed
- *   case-insensitive.
- * * Country codes and language codes are the same in both gettext and
- *   the Accept-Language syntax (except for the case differences, which
- *   are dealt with easily). If not, some input may be ignored.
- * * The provided gettext-strings are fully qualified; i.e., no "en_US";
- *   always "en_US.ISO-8859-15" or "en_US.UTF-8", or whichever has been
- *   used. "en.ISO-8859-15" is OK, though.
- * * The language is more important than the charset; i.e., if the
- *   following is given:
- * 
- *   Accept-Language: nl-be, nl;q=0.8, en-us;q=0.5, en;q=0.3
- *   Accept-Charset: ISO-8859-15, utf-8;q=0.5
- *
- *   And the supplied parameter contains (amongst others) nl_BE.UTF-8
- *   and nl.ISO-8859-15, then nl_BE.UTF-8 will be picked.
- * 
- * $Log: accept-to-gettext.inc,v $
- * Revision 1.1.1.1  2003/11/19 19:31:15  wouter
- * * moved to new CVS repo after death of the old
- * * Fixed code to apply a default to both Accept-Charset and
- *   Accept-Language if none of those headers are supplied; patch from
- *   Dominic Chambers <dominic at encasa.com>
- *
- * Revision 1.2  2003/08/14 10:23:59  wouter
- * Removed little error in Content-Type header syntaxis.
- *
- */
-
-/* not really important, this one; perhaps I could've put it inline with
- * the rest. */
-function find_match($curlscore,$curcscore,$curgtlang,$langval,$charval,
-                    $gtlang)
-{
-  if($curlscore < $langval) {
-    $curlscore=$langval;
-    $curcscore=$charval;
-    $curgtlang=$gtlang;
-  } else if ($curlscore == $langval) {
-    if($curcscore < $charval) {
-      $curcscore=$charval;
-      $curgtlang=$gtlang;
-    }
-  }
-  return array($curlscore, $curcscore, $curgtlang);
-}
-
-function al2gt($gettextlangs, $mime) {
-  /* default to "everything is acceptable", as RFC2616 specifies */
-  $acceptLang=(($_SERVER["HTTP_ACCEPT_LANGUAGE"] == '') ? '*' :
-  	$_SERVER["HTTP_ACCEPT_LANGUAGE"]);
-  $acceptChar=(($_SERVER["HTTP_ACCEPT_CHARSET"] == '') ? '*' :
-  	$_SERVER["HTTP_ACCEPT_CHARSET"]);
-  $alparts=@preg_split("/,/",$acceptLang);
-  $acparts=@preg_split("/,/",$acceptChar);
-  
-  /* Parse the contents of the Accept-Language header.*/
-  foreach($alparts as $part) {
-    $part=trim($part);
-    if(preg_match("/;/", $part)) {
-      $lang=@preg_split("/;/",$part);
-      $score=@preg_split("/=/",$lang[1]);
-      $alscores[$lang[0]]=$score[1];
-    } else {
-      $alscores[$part]=1;
-    }
-  }
-
-  /* Do the same for the Accept-Charset header. */
-
-  /* RFC2616: ``If no "*" is present in an Accept-Charset field, then
-   * all character sets not explicitly mentioned get a quality value of
-   * 0, except for ISO-8859-1, which gets a quality value of 1 if not
-   * explicitly mentioned.''
-   * 
-   * Making it 2 for the time being, so that we
-   * can distinguish between "not specified" and "specified as 1" later
-   * on. */
-  $acscores["ISO-8859-1"]=2;
-
-  foreach($acparts as $part) {
-    $part=trim($part);
-    if(preg_match("/;/", $part)) {
-      $cs=@preg_split("/;/",$part);
-      $score=@preg_split("/=/",$cs[1]);
-      $acscores[strtoupper($cs[0])]=$score[1];
-    } else {
-      $acscores[strtoupper($part)]=1;
-    }
-  }
-  if($acscores["ISO-8859-1"]==2) {
-    $acscores["ISO-8859-1"]=(isset($acscores["*"])?$acscores["*"]:1);
-  }
-
-  /* 
-   * Loop through the available languages/encodings, and pick the one
-   * with the highest score, excluding the ones with a charset the user
-   * did not include.
-   */
-  $curlscore=0;
-  $curcscore=0;
-  $curgtlang=NULL;
-  foreach($gettextlangs as $gtlang) {
-
-    $tmp1=preg_replace("/\_/","-",$gtlang);
-    $tmp2=@preg_split("/\./",$tmp1);
-    $allang=strtolower($tmp2[0]);
-    $gtcs=strtoupper($tmp2[1]);
-    $noct=@preg_split("/-/",$allang);
-
-    $testvals=array(
-         array($alscores[$allang], $acscores[$gtcs]),
-	 array($alscores[$noct[0]], $acscores[$gtcs]),
-	 array($alscores[$allang], $acscores["*"]),
-	 array($alscores[$noct[0]], $acscores["*"]),
-	 array($alscores["*"], $acscores[$gtcs]),
-	 array($alscores["*"], $acscores["*"]));
-
-    $found=FALSE;
-    foreach($testvals as $tval) {
-      if(!$found && isset($tval[0]) && isset($tval[1])) {
-        $arr=find_match($curlscore, $curcscore, $curgtlang, $tval[0],
-	          $tval[1], $gtlang);
-        $curlscore=$arr[0];
-        $curcscore=$arr[1];
-        $curgtlang=$arr[2];
-	$found=TRUE;
-      }
-    }
-  }
-
-  /* We must re-parse the gettext-string now, since we may have found it
-   * through a "*" qualifier.*/
-  
-  $gtparts=@preg_split("/\./",$curgtlang);
-  $tmp=strtolower($gtparts[0]);
-  $lang=preg_replace("/\_/", "-", $tmp);
-  $charset=$gtparts[1];
-
-  header("Content-Language: $lang");
-  header("Content-Type: $mime; charset=$charset");
-
-  return $curgtlang;
-}
-
-?>
diff --git a/externals/gettext.inc b/externals/gettext.inc
deleted file mode 100644
index 399a0f2..0000000
--- a/externals/gettext.inc
+++ /dev/null
@@ -1,534 +0,0 @@
-<?php
-/*
-   Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
-   Copyright (c) 2009 Danilo Segan <danilo at kvota.net>
-
-   Drop in replacement for native gettext.
-
-   This file is part of PHP-gettext.
-
-   PHP-gettext is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   PHP-gettext is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with PHP-gettext; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-*/
-/*
-LC_CTYPE        0
-LC_NUMERIC      1
-LC_TIME         2
-LC_COLLATE      3
-LC_MONETARY     4
-LC_MESSAGES     5
-LC_ALL          6
-*/
-
-
-// LC_MESSAGES is not available if php-gettext is not loaded
-// while the other constants are already available from session extension.
-if (!defined('LC_MESSAGES')) {
-  define('LC_MESSAGES',	5);
-}
-
-require('streams.php');
-require('gettext.php');
-
-
-// Variables
-
-global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE;
-$text_domains = array();
-$default_domain = 'messages';
-$LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL');
-$EMULATEGETTEXT = 0;
-$CURRENTLOCALE = '';
-
-/* Class to hold a single domain included in $text_domains. */
-class domain {
-  var $l10n;
-  var $path;
-  var $codeset;
-}
-
-// Utility functions
-
-/**
- * Return a list of locales to try for any POSIX-style locale specification.
- */
-function get_list_of_locales($locale) {
-  /* Figure out all possible locale names and start with the most
-   * specific ones.  I.e. for sr_CS.UTF-8 at latin, look through all of
-   * sr_CS.UTF-8 at latin, sr_CS at latin, sr at latin, sr_CS.UTF-8, sr_CS, sr.
-   */
-  $locale_names = array();
-  $lang = NULL;
-  $country = NULL;
-  $charset = NULL;
-  $modifier = NULL;
-  if ($locale) {
-    if (preg_match("/^(?P<lang>[a-z]{2,3})"              // language code
-                   ."(?:_(?P<country>[A-Z]{2}))?"           // country code
-                   ."(?:\.(?P<charset>[-A-Za-z0-9_]+))?"    // charset
-                   ."(?:@(?P<modifier>[-A-Za-z0-9_]+))?$/",  // @ modifier
-                   $locale, $matches)) {
-
-      if (isset($matches["lang"])) $lang = $matches["lang"];
-      if (isset($matches["country"])) $country = $matches["country"];
-      if (isset($matches["charset"])) $charset = $matches["charset"];
-      if (isset($matches["modifier"])) $modifier = $matches["modifier"];
-
-      if ($modifier) {
-        if ($country) {
-          if ($charset)
-            array_push($locale_names, "${lang}_$country.$charset@$modifier");
-          array_push($locale_names, "${lang}_$country@$modifier");
-        } elseif ($charset)
-            array_push($locale_names, "${lang}.$charset@$modifier");
-        array_push($locale_names, "$lang@$modifier");
-      }
-      if ($country) {
-        if ($charset)
-          array_push($locale_names, "${lang}_$country.$charset");
-        array_push($locale_names, "${lang}_$country");
-      } elseif ($charset)
-          array_push($locale_names, "${lang}.$charset");
-      array_push($locale_names, $lang);
-    }
-
-    // If the locale name doesn't match POSIX style, just include it as-is.
-    if (!in_array($locale, $locale_names))
-      array_push($locale_names, $locale);
-  }
-  return $locale_names;
-}
-
-/**
- * Utility function to get a StreamReader for the given text domain.
- */
-function _get_reader($domain=null, $category=5, $enable_cache=true) {
-    global $text_domains, $default_domain, $LC_CATEGORIES;
-    if (!isset($domain)) $domain = $default_domain;
-    if (!isset($text_domains[$domain]->l10n)) {
-        // get the current locale
-        $locale = _setlocale(LC_MESSAGES, 0);
-        $bound_path = isset($text_domains[$domain]->path) ?
-          $text_domains[$domain]->path : './';
-        $subpath = $LC_CATEGORIES[$category] ."/$domain.mo";
-
-        $locale_names = get_list_of_locales($locale);
-        $input = null;
-        foreach ($locale_names as $locale) {
-          $full_path = $bound_path . $locale . "/" . $subpath;
-          if (file_exists($full_path)) {
-            $input = new FileReader($full_path);
-            break;
-          }
-        }
-
-        if (!array_key_exists($domain, $text_domains)) {
-          // Initialize an empty domain object.
-          $text_domains[$domain] = new domain();
-        }
-        $text_domains[$domain]->l10n = new gettext_reader($input,
-                                                          $enable_cache);
-    }
-    return $text_domains[$domain]->l10n;
-}
-
-/**
- * Returns whether we are using our emulated gettext API or PHP built-in one.
- */
-function locale_emulation() {
-    global $EMULATEGETTEXT;
-    return $EMULATEGETTEXT;
-}
-
-/**
- * Checks if the current locale is supported on this system.
- */
-function _check_locale_and_function($function=false) {
-    global $EMULATEGETTEXT;
-    if ($function and !function_exists($function))
-        return false;
-    return !$EMULATEGETTEXT;
-}
-
-/**
- * Get the codeset for the given domain.
- */
-function _get_codeset($domain=null) {
-    global $text_domains, $default_domain, $LC_CATEGORIES;
-    if (!isset($domain)) $domain = $default_domain;
-    return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
-}
-
-/**
- * Convert the given string to the encoding set by bind_textdomain_codeset.
- */
-function _encode($text) {
-    $source_encoding = mb_detect_encoding($text);
-    $target_encoding = _get_codeset();
-    if ($source_encoding != $target_encoding) {
-        return mb_convert_encoding($text, $target_encoding, $source_encoding);
-    }
-    else {
-        return $text;
-    }
-}
-
-
-// Custom implementation of the standard gettext related functions
-
-/**
- * Returns passed in $locale, or environment variable $LANG if $locale == ''.
- */
-function _get_default_locale($locale) {
-  if ($locale == '') // emulate variable support
-    return getenv('LANG');
-  else
-    return $locale;
-}
-
-/**
- * Sets a requested locale, if needed emulates it.
- */
-function _setlocale($category, $locale) {
-    global $CURRENTLOCALE, $EMULATEGETTEXT;
-    if ($locale === 0) { // use === to differentiate between string "0"
-        if ($CURRENTLOCALE != '')
-            return $CURRENTLOCALE;
-        else
-            // obey LANG variable, maybe extend to support all of LC_* vars
-            // even if we tried to read locale without setting it first
-            return _setlocale($category, $CURRENTLOCALE);
-    } else {
-        if (function_exists('setlocale')) {
-          $ret = setlocale($category, $locale);
-          if (($locale == '' and !$ret) or // failed setting it by env
-              ($locale != '' and $ret != $locale)) { // failed setting it
-            // Failed setting it according to environment.
-            $CURRENTLOCALE = _get_default_locale($locale);
-            $EMULATEGETTEXT = 1;
-          } else {
-            $CURRENTLOCALE = $ret;
-            $EMULATEGETTEXT = 0;
-          }
-        } else {
-          // No function setlocale(), emulate it all.
-          $CURRENTLOCALE = _get_default_locale($locale);
-          $EMULATEGETTEXT = 1;
-        }
-        // Allow locale to be changed on the go for one translation domain.
-        global $text_domains, $default_domain;
-        unset($text_domains[$default_domain]->l10n);
-        return $CURRENTLOCALE;
-    }
-}
-
-/**
- * Sets the path for a domain.
- */
-function _bindtextdomain($domain, $path) {
-    global $text_domains;
-    // ensure $path ends with a slash ('/' should work for both, but lets still play nice)
-    if (substr(php_uname(), 0, 7) == "Windows") {
-      if ($path[strlen($path)-1] != '\\' and $path[strlen($path)-1] != '/')
-        $path .= '\\';
-    } else {
-      if ($path[strlen($path)-1] != '/')
-        $path .= '/';
-    }
-    if (!array_key_exists($domain, $text_domains)) {
-      // Initialize an empty domain object.
-      $text_domains[$domain] = new domain();
-    }
-    $text_domains[$domain]->path = $path;
-}
-
-/**
- * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned.
- */
-function _bind_textdomain_codeset($domain, $codeset) {
-    global $text_domains;
-    $text_domains[$domain]->codeset = $codeset;
-}
-
-/**
- * Sets the default domain.
- */
-function _textdomain($domain) {
-    global $default_domain;
-    $default_domain = $domain;
-}
-
-/**
- * Lookup a message in the current domain.
- */
-function _gettext($msgid) {
-    $l10n = _get_reader();
-    return _encode($l10n->translate($msgid));
-}
-
-/**
- * Alias for gettext.
- */
-function __($msgid) {
-    return _gettext($msgid);
-}
-
-/**
- * Plural version of gettext.
- */
-function _ngettext($single, $plural, $number) {
-    $l10n = _get_reader();
-    return _encode($l10n->ngettext($single, $plural, $number));
-}
-
-/**
- * Override the current domain.
- */
-function _dgettext($domain, $msgid) {
-    $l10n = _get_reader($domain);
-    return _encode($l10n->translate($msgid));
-}
-
-/**
- * Plural version of dgettext.
- */
-function _dngettext($domain, $single, $plural, $number) {
-    $l10n = _get_reader($domain);
-    return _encode($l10n->ngettext($single, $plural, $number));
-}
-
-/**
- * Overrides the domain and category for a single lookup.
- */
-function _dcgettext($domain, $msgid, $category) {
-    $l10n = _get_reader($domain, $category);
-    return _encode($l10n->translate($msgid));
-}
-/**
- * Plural version of dcgettext.
- */
-function _dcngettext($domain, $single, $plural, $number, $category) {
-    $l10n = _get_reader($domain, $category);
-    return _encode($l10n->ngettext($single, $plural, $number));
-}
-
-/**
- * Context version of gettext.
- */
-function _pgettext($context, $msgid) {
-    $l10n = _get_reader();
-    return _encode($l10n->pgettext($context, $msgid));
-}
-
-/**
- * Override the current domain in a context gettext call.
- */
-function _dpgettext($domain, $context, $msgid) {
-    $l10n = _get_reader($domain);
-    return _encode($l10n->pgettext($context, $msgid));
-}
-
-/**
- * Overrides the domain and category for a single context-based lookup.
- */
-function _dcpgettext($domain, $context, $msgid, $category) {
-    $l10n = _get_reader($domain, $category);
-    return _encode($l10n->pgettext($context, $msgid));
-}
-
-/**
- * Context version of ngettext.
- */
-function _npgettext($context, $singular, $plural) {
-    $l10n = _get_reader();
-    return _encode($l10n->npgettext($context, $singular, $plural));
-}
-
-/**
- * Override the current domain in a context ngettext call.
- */
-function _dnpgettext($domain, $context, $singular, $plural) {
-    $l10n = _get_reader($domain);
-    return _encode($l10n->npgettext($context, $singular, $plural));
-}
-
-/**
- * Overrides the domain and category for a plural context-based lookup.
- */
-function _dcnpgettext($domain, $context, $singular, $plural, $category) {
-    $l10n = _get_reader($domain, $category);
-    return _encode($l10n->npgettext($context, $singular, $plural));
-}
-
-
-
-// Wrappers to use if the standard gettext functions are available,
-// but the current locale is not supported by the system.
-// Use the standard impl if the current locale is supported, use the
-// custom impl otherwise.
-
-function T_setlocale($category, $locale) {
-    return _setlocale($category, $locale);
-}
-
-function T_bindtextdomain($domain, $path) {
-    if (_check_locale_and_function()) return bindtextdomain($domain, $path);
-    else return _bindtextdomain($domain, $path);
-}
-function T_bind_textdomain_codeset($domain, $codeset) {
-    // bind_textdomain_codeset is available only in PHP 4.2.0+
-    if (_check_locale_and_function('bind_textdomain_codeset'))
-        return bind_textdomain_codeset($domain, $codeset);
-    else return _bind_textdomain_codeset($domain, $codeset);
-}
-function T_textdomain($domain) {
-    if (_check_locale_and_function()) return textdomain($domain);
-    else return _textdomain($domain);
-}
-function T_gettext($msgid) {
-    if (_check_locale_and_function()) return gettext($msgid);
-    else return _gettext($msgid);
-}
-function T_($msgid) {
-    if (_check_locale_and_function()) return _($msgid);
-    return __($msgid);
-}
-function T_ngettext($single, $plural, $number) {
-    if (_check_locale_and_function())
-        return ngettext($single, $plural, $number);
-    else return _ngettext($single, $plural, $number);
-}
-function T_dgettext($domain, $msgid) {
-    if (_check_locale_and_function()) return dgettext($domain, $msgid);
-    else return _dgettext($domain, $msgid);
-}
-function T_dngettext($domain, $single, $plural, $number) {
-    if (_check_locale_and_function())
-        return dngettext($domain, $single, $plural, $number);
-    else return _dngettext($domain, $single, $plural, $number);
-}
-function T_dcgettext($domain, $msgid, $category) {
-    if (_check_locale_and_function())
-        return dcgettext($domain, $msgid, $category);
-    else return _dcgettext($domain, $msgid, $category);
-}
-function T_dcngettext($domain, $single, $plural, $number, $category) {
-    if (_check_locale_and_function())
-      return dcngettext($domain, $single, $plural, $number, $category);
-    else return _dcngettext($domain, $single, $plural, $number, $category);
-}
-
-function T_pgettext($context, $msgid) {
-  if (_check_locale_and_function('pgettext'))
-      return pgettext($context, $msgid);
-  else
-      return _pgettext($context, $msgid);
-}
-
-function T_dpgettext($domain, $context, $msgid) {
-  if (_check_locale_and_function('dpgettext'))
-      return dpgettext($domain, $context, $msgid);
-  else
-      return _dpgettext($domain, $context, $msgid);
-}
-
-function T_dcpgettext($domain, $context, $msgid, $category) {
-  if (_check_locale_and_function('dcpgettext'))
-      return dcpgettext($domain, $context, $msgid, $category);
-  else
-      return _dcpgettext($domain, $context, $msgid, $category);
-}
-
-function T_npgettext($context, $singular, $plural) {
-    if (_check_locale_and_function('npgettext'))
-        return npgettext($context, $single, $plural, $number);
-    else
-        return _npgettext($context, $single, $plural, $number);
-}
-
-function T_dnpgettext($domain, $context, $singular, $plural) {
-  if (_check_locale_and_function('dnpgettext'))
-      return dnpgettext($domain, $context, $single, $plural, $number);
-  else
-      return _dnpgettext($domain, $context, $single, $plural, $number);
-}
-
-function T_dcnpgettext($domain, $context, $singular, $plural, $category) {
-    if (_check_locale_and_function('dcnpgettext'))
-        return dcnpgettext($domain, $context, $single,
-                           $plural, $number, $category);
-    else
-        return _dcnpgettext($domain, $context, $single,
-                            $plural, $number, $category);
-}
-
-
-
-// Wrappers used as a drop in replacement for the standard gettext functions
-
-if (!function_exists('gettext')) {
-    function bindtextdomain($domain, $path) {
-        return _bindtextdomain($domain, $path);
-    }
-    function bind_textdomain_codeset($domain, $codeset) {
-        return _bind_textdomain_codeset($domain, $codeset);
-    }
-    function textdomain($domain) {
-        return _textdomain($domain);
-    }
-    function gettext($msgid) {
-        return _gettext($msgid);
-    }
-    function _($msgid) {
-        return __($msgid);
-    }
-    function ngettext($single, $plural, $number) {
-        return _ngettext($single, $plural, $number);
-    }
-    function dgettext($domain, $msgid) {
-        return _dgettext($domain, $msgid);
-    }
-    function dngettext($domain, $single, $plural, $number) {
-        return _dngettext($domain, $single, $plural, $number);
-    }
-    function dcgettext($domain, $msgid, $category) {
-        return _dcgettext($domain, $msgid, $category);
-    }
-    function dcngettext($domain, $single, $plural, $number, $category) {
-        return _dcngettext($domain, $single, $plural, $number, $category);
-    }
-    function pgettext($context, $msgid) {
-        return _pgettext($context, $msgid);
-    }
-    function npgettext($context, $single, $plural, $number) {
-        return _npgettext($context, $single, $plural, $number);
-    }
-    function dpgettext($domain, $context, $msgid) {
-        return _dpgettext($domain, $context, $msgid);
-    }
-    function dnpgettext($domain, $context, $single, $plural, $number) {
-        return _dnpgettext($domain, $context, $single, $plural, $number);
-    }
-    function dcpgettext($domain, $context, $msgid, $category) {
-        return _dcpgettext($domain, $context, $msgid, $category);
-    }
-    function dcnpgettext($domain, $context, $single, $plural,
-                         $number, $category) {
-      return _dcnpgettext($domain, $context, $single, $plural,
-                          $number, $category);
-    }
-}
-
-?>
diff --git a/externals/gettext.php b/externals/gettext.php
deleted file mode 100644
index d3826d8..0000000
--- a/externals/gettext.php
+++ /dev/null
@@ -1,425 +0,0 @@
-<?php
-/*
-   Copyright (c) 2003, 2009 Danilo Segan <danilo at kvota.net>.
-   Copyright (c) 2005 Nico Kaiser <nico at siriux.net>
-
-   This file is part of PHP-gettext.
-
-   PHP-gettext is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   PHP-gettext is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with PHP-gettext; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-*/
-
-/**
- * Provides a simple gettext replacement that works independently from
- * the system's gettext abilities.
- * It can read MO files and use them for translating strings.
- * The files are passed to gettext_reader as a Stream (see streams.php)
- *
- * This version has the ability to cache all strings and translations to
- * speed up the string lookup.
- * While the cache is enabled by default, it can be switched off with the
- * second parameter in the constructor (e.g. whenusing very large MO files
- * that you don't want to keep in memory)
- */
-class gettext_reader {
-  //public:
-   var $error = 0; // public variable that holds error code (0 if no error)
-
-   //private:
-  var $BYTEORDER = 0;        // 0: low endian, 1: big endian
-  var $STREAM = NULL;
-  var $short_circuit = false;
-  var $enable_cache = false;
-  var $originals = NULL;      // offset of original table
-  var $translations = NULL;    // offset of translation table
-  var $pluralheader = NULL;    // cache header field for plural forms
-  var $total = 0;          // total string count
-  var $table_originals = NULL;  // table for original strings (offsets)
-  var $table_translations = NULL;  // table for translated strings (offsets)
-  var $cache_translations = NULL;  // original -> translation mapping
-
-
-  /* Methods */
-
-
-  /**
-   * Reads a 32bit Integer from the Stream
-   *
-   * @access private
-   * @return Integer from the Stream
-   */
-  function readint() {
-      if ($this->BYTEORDER == 0) {
-        // low endian
-        $input=unpack('V', $this->STREAM->read(4));
-        return array_shift($input);
-      } else {
-        // big endian
-        $input=unpack('N', $this->STREAM->read(4));
-        return array_shift($input);
-      }
-    }
-
-  function read($bytes) {
-    return $this->STREAM->read($bytes);
-  }
-
-  /**
-   * Reads an array of Integers from the Stream
-   *
-   * @param int count How many elements should be read
-   * @return Array of Integers
-   */
-  function readintarray($count) {
-    if ($this->BYTEORDER == 0) {
-        // low endian
-        return unpack('V'.$count, $this->STREAM->read(4 * $count));
-      } else {
-        // big endian
-        return unpack('N'.$count, $this->STREAM->read(4 * $count));
-      }
-  }
-
-  /**
-   * Constructor
-   *
-   * @param object Reader the StreamReader object
-   * @param boolean enable_cache Enable or disable caching of strings (default on)
-   */
-  function gettext_reader($Reader, $enable_cache = true) {
-    // If there isn't a StreamReader, turn on short circuit mode.
-    if (! $Reader || isset($Reader->error) ) {
-      $this->short_circuit = true;
-      return;
-    }
-
-    // Caching can be turned off
-    $this->enable_cache = $enable_cache;
-
-    $MAGIC1 = "\x95\x04\x12\xde";
-    $MAGIC2 = "\xde\x12\x04\x95";
-
-    $this->STREAM = $Reader;
-    $magic = $this->read(4);
-    if ($magic == $MAGIC1) {
-      $this->BYTEORDER = 1;
-    } elseif ($magic == $MAGIC2) {
-      $this->BYTEORDER = 0;
-    } else {
-      $this->error = 1; // not MO file
-      return false;
-    }
-
-    // FIXME: Do we care about revision? We should.
-    $revision = $this->readint();
-
-    $this->total = $this->readint();
-    $this->originals = $this->readint();
-    $this->translations = $this->readint();
-  }
-
-  /**
-   * Loads the translation tables from the MO file into the cache
-   * If caching is enabled, also loads all strings into a cache
-   * to speed up translation lookups
-   *
-   * @access private
-   */
-  function load_tables() {
-    if (is_array($this->cache_translations) &&
-      is_array($this->table_originals) &&
-      is_array($this->table_translations))
-      return;
-
-    /* get original and translations tables */
-    if (!is_array($this->table_originals)) {
-      $this->STREAM->seekto($this->originals);
-      $this->table_originals = $this->readintarray($this->total * 2);
-    }
-    if (!is_array($this->table_translations)) {
-      $this->STREAM->seekto($this->translations);
-      $this->table_translations = $this->readintarray($this->total * 2);
-    }
-
-    if ($this->enable_cache) {
-      $this->cache_translations = array ();
-      /* read all strings in the cache */
-      for ($i = 0; $i < $this->total; $i++) {
-          $offset = $i * 2 + 2;
-          if (!($this && $this->table_originals[$offset])) {
-              continue;
-          }
-          $this->STREAM->seekto($this->table_originals[$offset]);
-          $original = $this->STREAM->read($this->table_originals[$offset - 1]);
-          $this->STREAM->seekto($this->table_translations[$offset]);
-          $translation = $this->STREAM->read($this->table_translations[$offset - 1]);
-          $this->cache_translations[$original] = $translation;
-      }
-    }
-  }
-
-  /**
-   * Returns a string from the "originals" table
-   *
-   * @access private
-   * @param int num Offset number of original string
-   * @return string Requested string if found, otherwise ''
-   */
-  function get_original_string($num) {
-    $length = $this->table_originals[$num * 2 + 1];
-    $offset = $this->table_originals[$num * 2 + 2];
-    if (! $length)
-      return '';
-    $this->STREAM->seekto($offset);
-    $data = $this->STREAM->read($length);
-    return (string)$data;
-  }
-
-  /**
-   * Returns a string from the "translations" table
-   *
-   * @access private
-   * @param int num Offset number of original string
-   * @return string Requested string if found, otherwise ''
-   */
-  function get_translation_string($num) {
-    $length = $this->table_translations[$num * 2 + 1];
-    $offset = $this->table_translations[$num * 2 + 2];
-    if (! $length)
-      return '';
-    $this->STREAM->seekto($offset);
-    $data = $this->STREAM->read($length);
-    return (string)$data;
-  }
-
-  /**
-   * Binary search for string
-   *
-   * @access private
-   * @param string string
-   * @param int start (internally used in recursive function)
-   * @param int end (internally used in recursive function)
-   * @return int string number (offset in originals table)
-   */
-  function find_string($string, $start = -1, $end = -1) {
-    if (($start == -1) or ($end == -1)) {
-      // find_string is called with only one parameter, set start end end
-      $start = 0;
-      $end = $this->total;
-    }
-    if (abs($start - $end) <= 1) {
-      // We're done, now we either found the string, or it doesn't exist
-      $txt = $this->get_original_string($start);
-      if ($string == $txt)
-        return $start;
-      else
-        return -1;
-    } else if ($start > $end) {
-      // start > end -> turn around and start over
-      return $this->find_string($string, $end, $start);
-    } else {
-      // Divide table in two parts
-      $half = (int)(($start + $end) / 2);
-      $cmp = strcmp($string, $this->get_original_string($half));
-      if ($cmp == 0)
-        // string is exactly in the middle => return it
-        return $half;
-      else if ($cmp < 0)
-        // The string is in the upper half
-        return $this->find_string($string, $start, $half);
-      else
-        // The string is in the lower half
-        return $this->find_string($string, $half, $end);
-    }
-  }
-
-  /**
-   * Translates a string
-   *
-   * @access public
-   * @param string string to be translated
-   * @return string translated string (or original, if not found)
-   */
-  function translate($string) {
-    if ($this->short_circuit)
-      return $string;
-    $this->load_tables();
-
-    if ($this->enable_cache) {
-      // Caching enabled, get translated string from cache
-      if (array_key_exists($string, $this->cache_translations))
-        return $this->cache_translations[$string];
-      else
-        return $string;
-    } else {
-      // Caching not enabled, try to find string
-      $num = $this->find_string($string);
-      if ($num == -1)
-        return $string;
-      else
-        return $this->get_translation_string($num);
-    }
-  }
-
-  /**
-   * Sanitize plural form expression for use in PHP eval call.
-   *
-   * @access private
-   * @return string sanitized plural form expression
-   */
-  function sanitize_plural_expression($expr) {
-    // Get rid of disallowed characters.
-    $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
-
-    // Add parenthesis for tertiary '?' operator.
-    $expr .= ';';
-    $res = '';
-    $p = 0;
-    for ($i = 0; $i < strlen($expr); $i++) {
-      $ch = $expr[$i];
-      switch ($ch) {
-      case '?':
-        $res .= ' ? (';
-        $p++;
-        break;
-      case ':':
-        $res .= ') : (';
-        break;
-      case ';':
-        $res .= str_repeat( ')', $p) . ';';
-        $p = 0;
-        break;
-      default:
-        $res .= $ch;
-      }
-    }
-    return $res;
-  }
-
-  /**
-   * Parse full PO header and extract only plural forms line.
-   *
-   * @access private
-   * @return string verbatim plural form header field
-   */
-  function extract_plural_forms_header_from_po_header($header) {
-    if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs))
-      $expr = $regs[2];
-    else
-      $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
-    return $expr;
-  }
-
-  /**
-   * Get possible plural forms from MO header
-   *
-   * @access private
-   * @return string plural form header
-   */
-  function get_plural_forms() {
-    // lets assume message number 0 is header
-    // this is true, right?
-    $this->load_tables();
-
-    // cache header field for plural forms
-    if (! is_string($this->pluralheader)) {
-      if ($this->enable_cache) {
-        $header = $this->cache_translations[""];
-      } else {
-        $header = $this->get_translation_string(0);
-      }
-      $expr = $this->extract_plural_forms_header_from_po_header($header);
-      $this->pluralheader = $this->sanitize_plural_expression($expr);
-    }
-    return $this->pluralheader;
-  }
-
-  /**
-   * Detects which plural form to take
-   *
-   * @access private
-   * @param n count
-   * @return int array index of the right plural form
-   */
-  function select_string($n) {
-    $string = $this->get_plural_forms();
-    $string = str_replace('nplurals',"\$total",$string);
-    $string = str_replace("n",$n,$string);
-    $string = str_replace('plural',"\$plural",$string);
-
-    $total = 0;
-    $plural = 0;
-
-    eval("$string");
-    if ($plural >= $total) $plural = $total - 1;
-    return $plural;
-  }
-
-  /**
-   * Plural version of gettext
-   *
-   * @access public
-   * @param string single
-   * @param string plural
-   * @param string number
-   * @return translated plural form
-   */
-  function ngettext($single, $plural, $number) {
-    if ($this->short_circuit) {
-      if ($number != 1)
-        return $plural;
-      else
-        return $single;
-    }
-
-    // find out the appropriate form
-    $select = $this->select_string($number);
-
-    // this should contains all strings separated by NULLs
-    $key = $single . chr(0) . $plural;
-
-
-    if ($this->enable_cache) {
-      if (! array_key_exists($key, $this->cache_translations)) {
-        return ($number != 1) ? $plural : $single;
-      } else {
-        $result = $this->cache_translations[$key];
-        $list = explode(chr(0), $result);
-        return $list[$select];
-      }
-    } else {
-      $num = $this->find_string($key);
-      if ($num == -1) {
-        return ($number != 1) ? $plural : $single;
-      } else {
-        $result = $this->get_translation_string($num);
-        $list = explode(chr(0), $result);
-        return $list[$select];
-      }
-    }
-  }
-
-  function pgettext($context, $msgid) {
-    $key = $context . chr(4) . $msgid;
-    return $this->translate($key);
-  }
-
-  function npgettext($context, $singular, $plural, $number) {
-    $singular = $context . chr(4) . $singular;
-    return $this->ngettext($singular, $plural, $number);
-  }
-}
-
-?>
diff --git a/externals/streams.php b/externals/streams.php
deleted file mode 100644
index 3cdc158..0000000
--- a/externals/streams.php
+++ /dev/null
@@ -1,167 +0,0 @@
-<?php
-/*
-   Copyright (c) 2003, 2005, 2006, 2009 Danilo Segan <danilo at kvota.net>.
-
-   This file is part of PHP-gettext.
-
-   PHP-gettext is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   PHP-gettext is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with PHP-gettext; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-*/
-
-
-  // Simple class to wrap file streams, string streams, etc.
-  // seek is essential, and it should be byte stream
-class StreamReader {
-  // should return a string [FIXME: perhaps return array of bytes?]
-  function read($bytes) {
-    return false;
-  }
-
-  // should return new position
-  function seekto($position) {
-    return false;
-  }
-
-  // returns current position
-  function currentpos() {
-    return false;
-  }
-
-  // returns length of entire stream (limit for seekto()s)
-  function length() {
-    return false;
-  }
-};
-
-class StringReader {
-  var $_pos;
-  var $_str;
-
-  function StringReader($str='') {
-    $this->_str = $str;
-    $this->_pos = 0;
-  }
-
-  function read($bytes) {
-    $data = substr($this->_str, $this->_pos, $bytes);
-    $this->_pos += $bytes;
-    if (strlen($this->_str)<$this->_pos)
-      $this->_pos = strlen($this->_str);
-
-    return $data;
-  }
-
-  function seekto($pos) {
-    $this->_pos = $pos;
-    if (strlen($this->_str)<$this->_pos)
-      $this->_pos = strlen($this->_str);
-    return $this->_pos;
-  }
-
-  function currentpos() {
-    return $this->_pos;
-  }
-
-  function length() {
-    return strlen($this->_str);
-  }
-
-};
-
-
-class FileReader {
-  var $_pos;
-  var $_fd;
-  var $_length;
-
-  function FileReader($filename) {
-    if (file_exists($filename)) {
-
-      $this->_length=filesize($filename);
-      $this->_pos = 0;
-      $this->_fd = fopen($filename,'rb');
-      if (!$this->_fd) {
-        $this->error = 3; // Cannot read file, probably permissions
-        return false;
-      }
-    } else {
-      $this->error = 2; // File doesn't exist
-      return false;
-    }
-  }
-
-  function read($bytes) {
-    if ($bytes) {
-      fseek($this->_fd, $this->_pos);
-
-      // PHP 5.1.1 does not read more than 8192 bytes in one fread()
-      // the discussions at PHP Bugs suggest it's the intended behaviour
-      $data = '';
-      while ($bytes > 0) {
-        $chunk  = fread($this->_fd, $bytes);
-        $data  .= $chunk;
-        $bytes -= strlen($chunk);
-      }
-      $this->_pos = ftell($this->_fd);
-
-      return $data;
-    } else return '';
-  }
-
-  function seekto($pos) {
-    fseek($this->_fd, $pos);
-    $this->_pos = ftell($this->_fd);
-    return $this->_pos;
-  }
-
-  function currentpos() {
-    return $this->_pos;
-  }
-
-  function length() {
-    return $this->_length;
-  }
-
-  function close() {
-    fclose($this->_fd);
-  }
-
-};
-
-// Preloads entire file in memory first, then creates a StringReader
-// over it (it assumes knowledge of StringReader internals)
-class CachedFileReader extends StringReader {
-  function CachedFileReader($filename) {
-    if (file_exists($filename)) {
-
-      $length=filesize($filename);
-      $fd = fopen($filename,'rb');
-
-      if (!$fd) {
-        $this->error = 3; // Cannot read file, probably permissions
-        return false;
-      }
-      $this->_str = fread($fd, $length);
-      fclose($fd);
-
-    } else {
-      $this->error = 2; // File doesn't exist
-      return false;
-    }
-  }
-};
-
-
-?>



Summary of changes:
 accept-to-gettext.inc | 184 -----------------
 externals/gettext.inc | 534 --------------------------------------------------
 externals/gettext.php | 425 ---------------------------------------
 externals/streams.php | 167 ----------------
 4 files changed, 1310 deletions(-)
 delete mode 100644 accept-to-gettext.inc
 delete mode 100644 externals/gettext.inc
 delete mode 100644 externals/gettext.php
 delete mode 100644 externals/streams.php



More information about the gnucash-changes mailing list