]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/_WikiTranslation.php
include [all] Include and file path should be devided with single space. File path...
[SourceForge/phpwiki.git] / lib / plugin / _WikiTranslation.php
1 <?php // -*-php-*-
2
3 /*
4  * Copyright 2004,2005 $ThePhpWikiProgrammingTeam
5  *
6  * This file is part of PhpWiki.
7  *
8  * PhpWiki is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * PhpWiki is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /**
24  * _WikiTranslation:  Display pagenames and other strings in various languages.
25  * Can also be used to let a favorite translation service translate a whole page.
26  * Current favorite: translate.google.com if from_lang = en or fr
27  *
28  * Examples:
29  *  <<_WikiTranslation page=HomePage languages=fr >>
30  *     Translation service for HomePage into french (redirect to translate.google.com)
31  *  <<_WikiTranslation what=pages >>
32  *     Translation matrix of all pages with proper translations (all in pgsrc)
33  *  <<_WikiTranslation what=wikiwords match="W*" limit=20 >>
34  *     Translation matrix of the first 20 wikiwords matching "W*"
35  *  <<_WikiTranslation string=HomePage languages=fr,de,sv >>
36  *     Translation matrix for all given languages
37  *  <<_WikiTranslation string=HomePage >>
38  *     Translation matrix for all supported languages
39  *  <<_WikiTranslation string=HomePage languages=fr >>
40  *     Just return the translated string for this language.
41  *
42  * @author:  Reini Urban
43  */
44
45 /* Container for untranslated pagenames. Needed to show up in locale/po/phpwiki.pot */
46 $pgsrc_container =
47     _("AllPagesCreatedByMe")  .','.
48     _("AllPagesLastEditedByMe")  .','.
49     _("AllPagesOwnedByMe")  .','.
50     _("BackLinks") .','.
51     _("CategoryCategory")  .','.
52     _("CategoryHomePages")  .','.
53     _("DebugInfo") .','.
54     _("EditMetaData") .','.
55     _("FindPage") .','.
56     _("FullRecentChanges") .','.
57     _("Help/AddingPages")  .','.
58     _("Help/AddCommentPlugin")  .','.
59     _("Help/AuthorHistoryPlugin") .','.
60     _("Help/CalendarListPlugin") .','.
61     _("Help/CalendarPlugin") .','.
62     _("Help/CommentPlugin")  .','.
63     _("Help/CreateTocPlugin")  .','.
64     _("Help/EditMetaDataPlugin") .','.
65     _("Help/ExternalSearchPlugin") .','.
66     _("Help/FoafViewerPlugin") .','.
67     _("Help/FrameIncludePlugin") .','.
68     _("Help/HelloWorldPlugin") .','.
69     _("Help/IncludePagePlugin") .','.
70     _("Help/LinkIcons") .','.
71     _("Help/MagicPhpWikiURLs") .','.
72     _("Help/MoreAboutMechanics") .','.
73     _("Help/OldStyleTablePlugin") .','.
74     _("Help/PhotoAlbumPlugin") .','.
75     _("Help/PhpHighlightPlugin") .','.
76     _("Help/PhpWeatherPlugin") .','.
77     _("Help/PhpWiki") .','.
78     _("Help/PloticusPlugin") .','.
79     _("Help/RawHtmlPlugin") .','.
80     _("Help/RedirectToPlugin") .','.
81     _("Help/RichTablePlugin") .','.
82     _("Help/SystemInfoPlugin") .','.
83     _("Help/TranscludePlugin") .','.
84     _("Help/UnfoldSubpagesPlugin") .','.
85     _("Help/UpLoadPlugin") .','.
86     _("Help/WabiSabi") .','.
87     _("Help/WikiBlogPlugin") .','.
88     _("Help/WikiPlugin") .','.
89     _("Help/WikiWikiWeb");
90     _("HomePageAlias") .','.
91     _("InterWiki") .','.
92 //  _("PageDump") .','.
93     _("PhpWikiAdministration/Chmod") .','.
94     _("PhpWikiAdministration/Chown") .','.
95     _("PhpWikiAdministration/Remove") .','.
96     _("PhpWikiAdministration/Rename") .','.
97     _("PhpWikiAdministration/Replace") .','.
98     _("PhpWikiAdministration/SetAcl") .','.
99     _("PhpWikiDocumentation") .','.
100     _("PhpWikiPoll") .','.
101     _("RecentVisitors") .','.
102     _("ReleaseNotes") .','.
103 //    _("SpellCheck") .','.
104     _("SteveWainstead") .','.
105     _("TranslateText") .','.
106     _("UpLoad") .','.
107
108 require_once 'lib/PageList.php';
109
110 class WikiPlugin__WikiTranslation
111 extends WikiPlugin
112 {
113
114     function getName() {
115         return _("_WikiTranslation");
116     }
117
118     function getDescription() {
119         return _("Show translations of various words or pages");
120     }
121
122     function getDefaultArguments() {
123         return array_merge
124             (
125              PageList::supportedArgs(),
126              array( 'languages'  => '',  // comma delimited string of de,en,sv,...
127                     'string'     => '',
128                     'page'       => '',  // use a translation service
129                     'what'       => 'pages', // or 'buttons', 'plugins' or 'wikiwords'
130
131                     'match'         => '*',
132                     'from_lang'     => false,
133                     'include_empty' => false,
134                     //'exclude'       => '',
135                     //'sortby'        => '',
136                     //'limit'         => 0,
137                     'nolinks'       => false,  // don't display any links
138                                                    // (for development only)
139                     'noT'           => false   // don't display the T link
140                                                   // (for development only)
141                     ));
142     }
143
144     function init_locale($lang) {
145         if ($lang != $this->lang)
146             update_locale($lang);
147         if ($lang == 'en') {
148             // Hack alert! we need hash for stepping through it, even if it's
149             // in the wrong language
150             include (FindFile("locale/de/LC_MESSAGES/phpwiki.php", 0,'reinit'));
151             foreach ($locale as $en => $de) {
152                     $locale[$en] = $en;
153             }
154         // gettext module loaded: must load the LC_MESSAGES php hash
155         } elseif (function_exists ('bindtextdomain')) {
156             include (FindFile("locale/$lang/LC_MESSAGES/phpwiki.php", 0,'reinit'));
157             //include (FindLocalizedFile("LC_MESSAGES/phpwiki.php", 0,'reinit'));
158         // we already have a $locale, but maybe it's in the wrong language
159         } elseif ($lang != $this->lang or empty($GLOBALS['locale'])) {
160             include (FindFile("locale/$lang/LC_MESSAGES/phpwiki.php", 0,'reinit'));
161         } else {
162            $locale = & $GLOBALS['locale'];
163         }
164         $this->_locales[$lang] = $locale;
165     }
166
167     // reverse translation:
168     function translate_to_en($text, $lang=false) {
169         if (!$lang) $lang = $this->lang; // current locale
170         if ($lang == 'en') return $text;
171
172         $this->_locales = array();
173         $this->_reverse_locales = array();
174
175         if (!isset($this->_locales[$lang])) {
176             $this->init_locale($lang);
177         }
178         assert(!empty($this->_locales[$lang]));
179         if (!isset($this->_reverse_locales[$lang])) {
180             // and now do a reverse lookup in the $locale hash
181             $this->_reverse_locales[$lang] = array_flip($this->_locales[$lang]);
182         }
183         if (!empty($this->_reverse_locales[$lang][$text])) {
184             return $this->_reverse_locales[$lang][$text];
185         } else {
186             return $text;
187         }
188     }
189
190     /**
191      * setlocale() switching with the gettext extension is by far too slow.
192      * So use the hash regardless if gettext is loaded or not.
193      */
194     function fast_translate($text, $to_lang, $from_lang=false) {
195         if (!$from_lang) $from_lang = $this->lang; // current locale
196         if ($from_lang == $to_lang) return $text;
197         // setup hash from en => to_lang
198         if (!isset($this->_locales[$to_lang]))
199             $this->init_locale($to_lang);
200         if ($from_lang != 'en') {
201             // get reverse gettext: translate to english
202             $text = $this->translate_to_en($text, $from_lang);
203         }
204         return !empty($this->_locales[$to_lang][$text])
205                  ? $this->_locales[$to_lang][$text]
206                  : $text;
207     }
208
209     //FIXME! There's something wrong.
210     function translate($text, $to_lang, $from_lang=false) {
211         if (!$from_lang) $from_lang = $this->lang; // current locale
212         if ($from_lang == $to_lang) return $text;
213         // Speed up hash lookup. Not needed for gettext module
214         if (!isset($this->_locales[$from_lang]) and !function_exists('bindtextdomain')) {
215             $this->init_locale($from_lang);
216         }
217         if ($from_lang != 'en') {
218             // get reverse gettext: translate to english
219             $en = $this->translate_to_en($text, $from_lang);
220             // and then to target
221             update_locale($to_lang);
222             $result = gettext($en);
223             update_locale($from_lang);
224         } else {
225             // locale switching is very slow with the gettext extension.
226             // better use fast_translate
227             if ($from_lang != $to_lang) {
228                 update_locale($to_lang);
229             }
230             $result = gettext($text);
231             if ($from_lang != $to_lang) {
232                 update_locale($from_lang);
233             }
234         }
235         return $result;
236     }
237
238     function run($dbi, $argstr, &$request, $basepage) {
239         $this->args = $this->getArgs($argstr, $request);
240         extract($this->args);
241         $this->request = &$request;
242         if (!$from_lang) $from_lang = $request->getPref('lang');
243         if (!$from_lang) $from_lang = $GLOBALS['LANG'];
244         $this->lang = $from_lang;
245
246         if (empty($languages)) {
247             $available_languages = listAvailableLanguages();
248             if ($from_lang == 'en') {
249                 // "en" is always the first.
250                 array_shift($available_languages);
251             }
252             // put from_lang to the very end.
253             if (in_array($from_lang, $available_languages))
254                 $languages = $available_languages;
255             else
256                     $languages = array_merge($available_languages, array($from_lang));
257         } elseif (strstr($languages,',')) {
258             $languages = explode(',', $languages);
259         } else {
260             $languages = array($languages);
261         }
262         if (in_array('zh', $languages) or in_array('ja', $languages)) {
263
264             // If the current charset != utf-8 the text will not be displayed correctly.
265             // But here we cannot change the header anymore. So we can decide to ignore them,
266             // or display them with all the errors.
267             //FIXME: do iconv the ob
268             if ($GLOBALS['charset'] != 'utf-8' and !defined('NEED_ICONV_TO')) {
269                     define('NEED_ICONV_TO', 'utf-8');
270                     //either the extension or external
271                 //$GLOBALS['charset'] = 'utf-8';
272             }
273         }
274         $to_lang = $languages[0];
275         if (!empty($string) and count($languages)==1) {
276             return $this->translate($string, $to_lang, $from_lang);
277         }
278         if (!empty($page)) {
279             $pagename = $page;
280             if ($dbi->isWikiPage($pagename)) {
281                     $url = '';
282                     // google can only translate from english and french
283                     if (in_array($from_lang, array('en', 'fr'))) {
284                     $url = "http://translate.google.com/translate";
285                     $url .= "?langpair=" . urlencode($from_lang."|".$to_lang);
286                     $url .= "&u=" . urlencode(WikiURL($pagename, false, true));
287                     }
288                     // redirect or transclude?
289                 if ($url) {
290                     return $request->redirect($url);
291                 }
292                     return HTML(fmt("TODO: Google can only translate from english and french. Find a translation service for %s to language %s",
293                                     WikiURL($pagename, false, true),
294                                     $to_lang));
295             } else {
296                 return $this->error(fmt("%s is empty",$pagename));
297             }
298         }
299
300         $pagelist = new PageList('', $exclude, $this->args);
301         $pagelist->_columns[0]->_heading = "$from_lang";
302         foreach ($languages as $lang) {
303             if ($lang == $from_lang) continue;
304             $field = "custom:$lang";
305             $pagelist->addColumnObject (
306               new _PageList_Column_customlang($field, $from_lang, $this));
307         }
308         if (!empty($string)) {
309             $pagelist->addPage( $string );
310             return $pagelist;
311         }
312         switch ($what) {
313         case 'allpages':
314             $pagelist->addPages( $dbi->getAllPages($include_empty, $sortby,
315                                                    $limit, $exclude) );
316             break;
317         case 'pages':
318             // not all pages, only the pgsrc pages
319             if (!is_array($exclude))
320                 $exclude = $pagelist->explodePageList($exclude, false, $sortby,
321                                                       $limit, $exclude);
322             $path = FindLocalizedFile(WIKI_PGSRC);
323             $pgsrc = new fileSet($path);
324             foreach ($pgsrc->getFiles($exclude, $sortby, $limit) as $pagename) {
325                 $pagename = urldecode($pagename);
326                 if (substr($pagename,-1,1) == '~') continue;
327                 if (in_array($pagename, $exclude))
328                     continue;             // exclude page.
329                 if ($match != '*' and !glob_match($match, $pagename))
330                     continue;
331                 $page_handle = $dbi->getPage($pagename);
332                 $pagelist->addPage( $page_handle );
333             }
334             break;
335         case 'wikiwords':
336             if (!isset($this->_locales[$from_lang])) {
337                 $this->init_locale($from_lang);
338             }
339             $locale = & $this->_locales[$from_lang];
340             if (is_array($locale)) {
341                 $count = 0;
342                 foreach ($locale as $from => $to) {
343                     if ($match != '*' and !glob_match($match, $from))
344                         continue;
345                     if (isWikiWord($from)) {
346                         $count++;
347                         $pagelist->addPage( $from );
348                         if ($limit and $count > $limit) break;
349                     }
350                 }
351             }
352             break;
353         // all Button texts, which need a localized .png
354         // where to get them from? templates/*.tmpl: Button()
355         // and WikiLink(?,'button')
356         // navbar links, actionpages, and admin requests
357         case 'buttons':
358             $buttons = $GLOBALS['AllActionPages'];
359             $fileset = new FileSet(FindFile("themes/MacOSX/buttons/en"),
360                                    "*.png");
361             foreach ($fileset->getFiles() as $file) {
362                 $b = urldecode(substr($file, 0, -4));
363                 if (!in_array($b,$buttons))
364                     $buttons[] = $b;
365             }
366             $count = 0;
367             foreach ($buttons as $button) {
368                 $pagelist->addPage( $button );
369                 if ($limit and ++$count > $limit) break;
370             }
371             break;
372         }
373         return $pagelist;
374     }
375 };
376
377 class _PageList_Column_customlang extends _PageList_Column {
378     function _PageList_Column_customlang($field, $from_lang, $plugin) {
379         $this->_field = $field;
380         $this->_from_lang = $from_lang;
381         $this->_plugin =& $plugin;
382         $this->_what = $plugin->args['what'];
383         $this->_noT = $plugin->args['noT'];
384         $this->_nolinks = $plugin->args['nolinks'];
385         $this->_iscustom = substr($field, 0, 7) == 'custom:';
386         if ($this->_iscustom)
387             $this->_field = substr($field, 7);
388         //$heading = $field;
389         $this->dbi = &$GLOBALS['request']->getDbh();
390         $this->_PageList_Column_base($this->_field);
391     }
392
393     function _getValue($page, &$revision_handle) {
394             if (is_object($page)) $text = $page->getName();
395         else $text = $page;
396             $trans = $this->_plugin->fast_translate($text, $this->_field,
397                                                 $this->_from_lang);
398         // how to markup untranslated words and not existing pages?
399         // untranslated: (TODO) link to translation editor
400         if ($trans == $text or // untranslated
401             (($this->_from_lang != 'en') and
402              ($this->_field != 'en') and
403              ($trans == $this->_plugin->fast_translate($text, 'en',
404                                                        $this->_from_lang))
405              ))
406         {
407             global $WikiTheme;
408             $link = $WikiTheme->linkUnknownWikiWord($trans);
409             if (!($this->_noT or $this->_nolinks)
410                 and $this->dbi->isWikiPage($trans))
411             {
412                 $url = WikiURL($trans, array('action' => 'TranslateText',
413                                              'lang' => $this->_field));
414                 $button = $WikiTheme->makeButton('T', $url);
415                 $button->addTooltip(sprintf(_("Define the translation for %s in %s"),
416                                             $trans, $this->_field));
417                 $link = HTML::span($button);
418                 $link->setAttr('class', 'wikiunknown');
419                 $text = HTML::span($WikiTheme->maybeSplitWikiWord($trans));
420                 $text->setAttr('style', 'text-decoration:line-through');
421                 $link->pushContent($text);
422                 return $link;
423             } elseif (is_object($page))
424                 return '';
425             else                        // not existing: empty
426                 return '';
427         } elseif (is_object($page)) {
428             if (!$this->_nolinks)
429                 return WikiLink($trans, 'auto');
430             else
431                 return $trans;
432         } else {
433             return $trans;
434         }
435     }
436 }
437
438 // Local Variables:
439 // mode: php
440 // tab-width: 8
441 // c-basic-offset: 4
442 // c-hanging-comment-ender-p: nil
443 // indent-tabs-mode: nil
444 // End: