summaryrefslogtreecommitdiff
path: root/platform/www/lib/plugins/translation/helper.php
diff options
context:
space:
mode:
Diffstat (limited to 'platform/www/lib/plugins/translation/helper.php')
-rw-r--r--platform/www/lib/plugins/translation/helper.php446
1 files changed, 446 insertions, 0 deletions
diff --git a/platform/www/lib/plugins/translation/helper.php b/platform/www/lib/plugins/translation/helper.php
new file mode 100644
index 0000000..e6bc3b5
--- /dev/null
+++ b/platform/www/lib/plugins/translation/helper.php
@@ -0,0 +1,446 @@
+<?php
+/**
+ * Translation Plugin: Simple multilanguage plugin
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+
+// must be run within Dokuwiki
+if(!defined('DOKU_INC')) die();
+
+/**
+ * Class helper_plugin_translation
+ */
+class helper_plugin_translation extends DokuWiki_Plugin {
+ var $translations = array();
+ var $translationNs = '';
+ var $defaultlang = '';
+ var $LN = array(); // hold native names
+ var $opts = array(); // display options
+
+ /**
+ * Initialize
+ */
+ function __construct() {
+ global $conf;
+ require_once(DOKU_INC . 'inc/pageutils.php');
+ require_once(DOKU_INC . 'inc/utf8.php');
+
+ $this->loadTranslationNamespaces();
+
+ // load language names
+ $this->LN = confToHash(dirname(__FILE__) . '/lang/langnames.txt');
+
+ // display options
+ $this->opts = $this->getConf('display');
+ $this->opts = explode(',', $this->opts);
+ $this->opts = array_map('trim', $this->opts);
+ $this->opts = array_fill_keys($this->opts, true);
+
+ // get default translation
+ if(!empty($conf['lang_before_translation'])) {
+ $dfl = $conf['lang'];
+ } else {
+ $dfl = $conf['lang_before_translation'];
+ }
+ if(in_array($dfl, $this->translations)) {
+ $this->defaultlang = $dfl;
+ } else {
+ $this->defaultlang = '';
+ array_unshift($this->translations, '');
+ }
+
+ $this->translationNs = cleanID($this->getConf('translationns'));
+ if($this->translationNs) $this->translationNs .= ':';
+ }
+
+ /**
+ * Parse 'translations'-setting into $this->translations
+ */
+ public function loadTranslationNamespaces() {
+ // load wanted translation into array
+ $this->translations = strtolower(str_replace(',', ' ', $this->getConf('translations')));
+ $this->translations = array_unique(array_filter(explode(' ', $this->translations)));
+ sort($this->translations);
+ }
+
+ /**
+ * Check if the given ID is a translation and return the language code.
+ *
+ * @param string $id
+ * @return string
+ */
+ function getLangPart($id) {
+ list($lng) = $this->getTransParts($id);
+ return $lng;
+ }
+
+ /**
+ * Check if the given ID is a translation and return the language code and
+ * the id part.
+ *
+ * @param string $id
+ * @return array
+ */
+ function getTransParts($id) {
+ $rx = '/^' . $this->translationNs . '(' . join('|', $this->translations) . '):(.*)/';
+ if(preg_match($rx, $id, $match)) {
+ return array($match[1], $match[2]);
+ }
+ return array('', $id);
+ }
+
+ /**
+ * Returns the browser language if it matches with one of the configured
+ * languages
+ */
+ function getBrowserLang() {
+ global $conf;
+ $langs = $this->translations;
+ if (!in_array($conf['lang'], $langs)) {
+ $langs[] = $conf['lang'];
+ }
+ $rx = '/(^|,|:|;|-)(' . join('|', $langs) . ')($|,|:|;|-)/i';
+ if(preg_match($rx, $_SERVER['HTTP_ACCEPT_LANGUAGE'], $match)) {
+ return strtolower($match[2]);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the ID and name to the wanted translation, empty
+ * $lng is default lang
+ *
+ * @param string $lng
+ * @param string $idpart
+ * @return array
+ */
+ function buildTransID($lng, $idpart) {
+ if($lng && in_array($lng, $this->translations)) {
+ $link = ':' . $this->translationNs . $lng . ':' . $idpart;
+ $name = $lng;
+ } else {
+ $link = ':' . $this->translationNs . $idpart;
+ $name = $this->realLC('');
+ }
+ return array($link, $name);
+ }
+
+ /**
+ * Returns the real language code, even when an empty one is given
+ * (eg. resolves th default language)
+ *
+ * @param string $lc
+ * @return string
+ */
+ function realLC($lc) {
+ global $conf;
+ if($lc) {
+ return $lc;
+ } elseif(!$conf['lang_before_translation']) {
+ return $conf['lang'];
+ } else {
+ return $conf['lang_before_translation'];
+ }
+ }
+
+ /**
+ * Check if current ID should be translated and any GUI
+ * should be shown
+ *
+ * @param string $id
+ * @param bool $checkact
+ * @return bool
+ */
+ function istranslatable($id, $checkact = true) {
+ global $ACT;
+
+ if($checkact && $ACT != 'show') return false;
+ if($this->translationNs && strpos($id, $this->translationNs) !== 0) return false;
+ $skiptrans = trim($this->getConf('skiptrans'));
+ if($skiptrans && preg_match('/' . $skiptrans . '/ui', ':' . $id)) return false;
+ $meta = p_get_metadata($id);
+ if(!empty($meta['plugin']['translation']['notrans'])) return false;
+
+ return true;
+ }
+
+ /**
+ * Return the (localized) about link
+ */
+ function showAbout() {
+ global $ID;
+
+ $curlc = $this->getLangPart($ID);
+
+ $about = $this->getConf('about');
+ if($this->getConf('localabout')) {
+ list(/* $lc */, $idpart) = $this->getTransParts($about);
+ list($about, /* $name */) = $this->buildTransID($curlc, $idpart);
+ $about = cleanID($about);
+ }
+
+ $out = '';
+ $out .= '<sup>';
+ $out .= html_wikilink($about, '?');
+ $out .= '</sup>';
+
+ return $out;
+ }
+
+ /**
+ * Returns a list of (lc => link) for all existing translations of a page
+ *
+ * @param $id
+ * @return array
+ */
+ function getAvailableTranslations($id) {
+ $result = array();
+
+ list($lc, $idpart) = $this->getTransParts($id);
+
+ foreach($this->translations as $t) {
+ if($t == $lc) continue; //skip self
+ list($link, $name) = $this->buildTransID($t, $idpart);
+ if(page_exists($link)) {
+ $result[$name] = $link;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Creates an UI for linking to the available and configured translations
+ *
+ * Can be called from the template or via the ~~TRANS~~ syntax component.
+ */
+ public function showTranslations() {
+ global $conf;
+ global $INFO;
+
+ if(!$this->istranslatable($INFO['id'])) return '';
+ $this->checkage();
+
+ list($lc, $idpart) = $this->getTransParts($INFO['id']);
+ $lang = $this->realLC($lc);
+
+ $out = '<div class="plugin_translation">';
+
+ //show title and about
+ if(isset($this->opts['title'])) {
+ $out .= '<span>' . $this->getLang('translations');
+ if($this->getConf('about')) $out .= $this->showAbout();
+ $out .= ':</span> ';
+ if(isset($this->opts['twolines'])) $out .= '<br />';
+ }
+
+ // open wrapper
+ if($this->getConf('dropdown')) {
+ // select needs its own styling
+ if($INFO['exists']) {
+ $class = 'wikilink1';
+ } else {
+ $class = 'wikilink2';
+ }
+ if(isset($this->opts['flag'])) {
+ $flag = DOKU_BASE . 'lib/plugins/translation/flags/' . hsc($lang) . '.gif';
+ }else{
+ $flag = '';
+ }
+
+ if($conf['userewrite']) {
+ $action = wl();
+ } else {
+ $action = script();
+ }
+
+ $out .= '<form action="' . $action . '" id="translation__dropdown">';
+ if($flag) $out .= '<img src="' . $flag . '" alt="' . hsc($lang) . '" height="11" class="' . $class . '" /> ';
+ $out .= '<select name="id" class="' . $class . '">';
+ } else {
+ $out .= '<ul>';
+ }
+
+ // insert items
+
+ array_shift($this->translations);
+ foreach($this->translations as $t) {
+ $out .= $this->getTransItem($t, $idpart);
+ }
+
+ // close wrapper
+ if($this->getConf('dropdown')) {
+ $out .= '</select>';
+ $out .= '<input name="go" type="submit" value="&rarr;" />';
+ $out .= '</form>';
+ } else {
+ $out .= '</ul>';
+ }
+
+ // show about if not already shown
+ if(!isset($this->opts['title']) && $this->getConf('about')) {
+ $out .= '&nbsp';
+ $out .= $this->showAbout();
+ }
+
+ $out .= '</div>';
+
+ return $out;
+ }
+
+ /**
+ * Return the local name
+ *
+ * @param $lang
+ * @return string
+ */
+ function getLocalName($lang) {
+ if($this->LN[$lang]) {
+ return $this->LN[$lang];
+ }
+ return $lang;
+ }
+
+ /**
+ * Create the link or option for a single translation
+ *
+ * @param $lc string The language code
+ * @param $idpart string The ID of the translated page
+ * @returns string The item
+ */
+ function getTransItem($lc, $idpart) {
+ global $ID;
+ global $conf;
+
+ list($link, $lang) = $this->buildTransID($lc, $idpart);
+ $link = cleanID($link);
+
+ // class
+ if(page_exists($link, '', false)) {
+ $class = 'wikilink1';
+ } else {
+ $class = 'wikilink2';
+ }
+
+ // local language name
+ $localname = $this->getLocalName($lang);
+
+ $divClass = 'li';
+ // current?
+ if($ID == $link) {
+ $sel = ' selected="selected"';
+ $class .= ' cur';
+ $divClass .= ' cur';
+ } else {
+ $sel = '';
+ }
+
+ // flag
+ $flag = false;
+ $style = '';
+ if(isset($this->opts['flag'])) {
+ $flag = DOKU_BASE . 'lib/plugins/translation/flags/' . hsc($lang) . '.gif';
+ $style = ' style="background-image: url(\'' . $flag . '\')"';
+ $class .= ' flag';
+ }
+
+ // what to display as name
+ if(isset($this->opts['name'])) {
+ $display = hsc($localname);
+ if(isset($this->opts['langcode'])) $display .= ' (' . hsc($lang) . ')';
+ } elseif(isset($this->opts['langcode'])) {
+ $display = hsc($lang);
+ } else {
+ $display = '&nbsp;';
+ }
+
+ // prepare output
+ $out = '';
+ if($this->getConf('dropdown')) {
+ if($conf['useslash']) $link = str_replace(':', '/', $link);
+
+ $out .= '<option class="' . $class . '" title="' . hsc($localname) . '" value="' . $link . '"' . $sel . $style . '>';
+ $out .= $display;
+ $out .= '</option>';
+ } else {
+ $out .= "<li><div class='$divClass'>";
+ $out .= '<a href="' . wl($link) . '" class="' . $class . '" title="' . hsc($localname) . '">';
+ if($flag) $out .= '<img src="' . $flag . '" alt="' . hsc($lang) . '" height="11" />';
+ $out .= $display;
+ $out .= '</a>';
+ $out .= '</div></li>';
+ }
+
+ return $out;
+ }
+
+ /**
+ * Checks if the current page is a translation of a page
+ * in the default language. Displays a notice when it is
+ * older than the original page. Tries to link to a diff
+ * with changes on the original since the translation
+ */
+ function checkage() {
+ global $ID;
+ global $INFO;
+ if(!$this->getConf('checkage')) return;
+ if(!$INFO['exists']) return;
+ $lng = $this->getLangPart($ID);
+ if($lng == $this->defaultlang) return;
+
+ $rx = '/^' . $this->translationNs . '((' . join('|', $this->translations) . '):)?/';
+ $idpart = preg_replace($rx, '', $ID);
+
+ // compare modification times
+ list($orig, /* $name */) = $this->buildTransID($this->defaultlang, $idpart);
+ $origfn = wikiFN($orig);
+ if($INFO['lastmod'] >= @filemtime($origfn)) return;
+
+ // get revision from before translation
+ $orev = 0;
+
+ $changelog = new PageChangelog($orig);
+ $revs = $changelog->getRevisions(0, 100);
+ foreach($revs as $rev) {
+ if($rev < $INFO['lastmod']) {
+ $orev = $rev;
+ break;
+ }
+ }
+
+ // see if the found revision still exists
+ if($orev && !page_exists($orig, $orev)) $orev = 0;
+
+ // build the message and display it
+ $orig = cleanID($orig);
+ $msg = sprintf($this->getLang('outdated'), wl($orig));
+
+ $difflink = $this->getOldDiffLink($orig, $INFO['lastmod']);
+ if ($difflink) {
+ $msg .= sprintf(' ' . $this->getLang('diff'), $difflink);
+ }
+
+ echo '<div class="notify">' . $msg . '</div>';
+ }
+
+ function getOldDiffLink($id, $lastmod) {
+ // get revision from before translation
+ $orev = false;
+ $changelog = new PageChangelog($id);
+ $revs = $changelog->getRevisions(0, 100);
+ foreach($revs as $rev) {
+ if($rev < $lastmod) {
+ $orev = $rev;
+ break;
+ }
+ }
+ if($orev && !page_exists($id, $orev)) {
+ return false;
+ }
+ $id = cleanID($id);
+ return wl($id, array('do' => 'diff', 'rev' => $orev));
+
+ }
+}