2 rcs_id('$Id: _WikiTranslation.php,v 1.14 2004-07-08 20:30:07 rurban Exp $');
4 Copyright 2004 $ThePhpWikiProgrammingTeam
6 This file is part of PhpWiki.
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.
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.
18 You should have received a copy of the GNU General Public License
19 along with PhpWiki; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
29 * <?plugin _WikiTranslation page=HomePage languages=fr ?>
30 * Translation service for HomePage into french (redirect to translate.google.com)
31 * <?plugin _WikiTranslation what=pages ?>
32 * Translation matrix of all pages with proper translations (all in pgsrc)
33 * <?plugin _WikiTranslation what=wikiwords match="W*" limit=20 ?>
34 * Translation matrix of the first 20 wikiwords matching "W*"
35 * <?plugin _WikiTranslation string=HomePage languages=fr,de,sv ?>
36 * Translation matrix for all given languages
37 * <?plugin _WikiTranslation string=HomePage ?>
38 * Translation matrix for all supported languages
39 * <?plugin _WikiTranslation string=HomePage languages=fr ?>
40 * Just return the translated string for this language.
42 * @author: Reini Urban
45 /* Container for untranslated pagenames. Needed to show up in locale/po/phpwiki.pot */
47 _("AddCommentPlugin") .','.
48 _("AddingPages") .','.
49 _("AllPagesCreatedByMe") .','.
50 _("AllPagesLastEditedByMe") .','.
51 _("AllPagesOwnedByMe") .','.
52 _("AuthorHistoryPlugin") .','.
54 _("CalendarListPlugin") .','.
55 _("CalendarPlugin") .','.
56 _("CategoryCategory") .','.
57 _("CategoryHomePages") .','.
58 _("CommentPlugin") .','.
59 _("CreateTocPlugin") .','.
61 _("EditMetaData") .','.
62 _("EditMetaDataPlugin") .','.
63 _("ExternalSearchPlugin") .','.
65 _("FoafViewerPlugin") .','.
66 _("FrameIncludePlugin") .','.
67 _("FullRecentChanges") .','.
68 _("HelloWorldPlugin") .','.
69 _("HomePageAlias") .','.
70 _("IncludePagePlugin") .','.
73 _("MagicPhpWikiURLs") .','.
74 _("MoreAboutMechanics") .','.
75 _("NewMarkupTestPage") .','.
76 _("OldMarkupTestPage") .','.
77 _("OldStyleTablePlugin") .','.
78 // _("PageDump") .','.
79 _("PageGroupTest") .','.
80 _("PageGroupTest/Four") .','.
81 _("PageGroupTest/One") .','.
82 _("PageGroupTest/Three") .','.
83 _("PageGroupTest/Two") .','.
84 _("PgsrcTranslation") .','.
85 _("PhotoAlbumPlugin") .','.
86 _("PhpHighlightPlugin") .','.
87 _("PhpWeatherPlugin") .','.
89 _("PhpWikiAdministration/Chmod") .','.
90 _("PhpWikiAdministration/Chown") .','.
91 _("PhpWikiAdministration/Remove") .','.
92 _("PhpWikiAdministration/Rename") .','.
93 _("PhpWikiAdministration/Replace") .','.
94 _("PhpWikiDocumentation") .','.
95 _("PhpWikiPoll") .','.
96 _("PloticusPlugin") .','.
97 _("RawHtmlPlugin") .','.
98 _("RecentVisitors") .','.
99 _("RedirectToPlugin") .','.
100 _("ReleaseNotes") .','.
101 _("RichTablePlugin") .','.
102 _("SteveWainstead") .','.
103 _("SystemInfoPlugin") .','.
104 _("TranscludePlugin") .','.
105 _("TranslateText") .','.
106 _("UnfoldSubpagesPlugin") .','.
108 _("UpLoadPlugin") .','.
110 _("WikiBlogPlugin") .','.
111 _("WikiPlugin") .','.
114 require_once('lib/PageList.php');
116 class WikiPlugin__WikiTranslation
121 return _("_WikiTranslation");
124 function getDescription() {
125 return _("Show translations of various words or pages");
128 function getVersion() {
129 return preg_replace("/[Revision: $]/", '',
130 "\$Revision: 1.14 $");
133 function getDefaultArguments() {
135 array( 'languages' => '', // comma delimited string of de,en,sv,...
137 'page' => '', // use a translation service
138 'what' => 'pages', // or 'buttons', 'plugins' or 'wikiwords'
141 'from_lang' => false,
142 'include_empty' => false,
146 'nolinks' => false, // don't display any links (for development only)
147 'noT' => false, // don't display the T link (for development only)
152 function init_locale($lang) {
153 if ($lang != $this->lang)
154 update_locale($lang);
156 //hack alert! we need hash for stepping through it, even if it's in the wrong language
157 include (FindFile("locale/de/LC_MESSAGES/phpwiki.php", 0,'reinit'));
158 foreach ($locale as $en => $de) {
161 // gettext module loaded: must load the LC_MESSAGES php hash
162 } elseif (function_exists ('bindtextdomain')) {
163 include (FindLocalizedFile("LC_MESSAGES/phpwiki.php", 0,'reinit'));
164 // we already have a $locale, but maybe it's in the wrong language
165 } elseif ($lang != $this->lang or empty($GLOBALS['locale'])) {
166 include (FindFile("locale/$lang/LC_MESSAGES/phpwiki.php", 0,'reinit'));
168 $locale = & $GLOBALS['locale'];
170 $this->_locales[$lang] = $locale;
173 // reverse translation:
174 function translate_to_en($text, $lang=false) {
175 if (!$lang) $lang = $this->lang; // current locale
176 if ($lang == 'en') return $text;
178 $this->_locales = array();
179 $this->_reverse_locales = array();
181 if (!isset($this->_locales[$lang])) {
182 $this->init_locale($lang);
184 assert(!empty($this->_locales[$lang]));
185 if (!isset($this->_reverse_locales[$lang])) {
186 // and now do a reverse lookup in the $locale hash
187 $this->_reverse_locales[$lang] = array_flip($this->_locales[$lang]);
189 if (!empty($this->_reverse_locales[$lang][$text])) {
190 return $this->_reverse_locales[$lang][$text];
196 function translate($text, $to_lang, $from_lang=false) {
197 if (!$from_lang) $from_lang = $this->lang; // current locale
198 if ($from_lang == $to_lang) return $text;
199 // speed up hash lookup. not needed for gettext module
200 if (!isset($this->_locales[$from_lang]) and !function_exists('bindtextdomain')) {
201 $this->init_locale($from_lang);
203 if ($from_lang != 'en') {
204 // get reverse gettext: translate to english
205 $en = $this->translate_to_en($text,$from_lang);
206 // and then to target
207 update_locale($to_lang);
208 $result = gettext($en);
209 update_locale($from_lang);
211 if ($from_lang != $to_lang) {
212 update_locale($to_lang);
214 $result = gettext($text);
215 if ($from_lang != $to_lang) {
216 update_locale($from_lang);
222 function run($dbi, $argstr, &$request, $basepage) {
223 $this->args = $this->getArgs($argstr, $request);
224 extract($this->args);
225 $this->request = &$request;
226 if (!$from_lang) $from_lang = $request->getPref('lang');
227 if (!$from_lang) $from_lang = $GLOBALS['LANG'];
228 $this->lang = $from_lang;
230 if (empty($languages)) {
231 $available_languages = listAvailableLanguages();
232 if ($from_lang == 'en') {
233 // "en" is always the first.
234 array_shift($available_languages);
236 // put from_lang to the very end.
237 if (in_array($from_lang, $available_languages))
238 $languages = $available_languages;
240 $languages = array_merge($available_languages, array($from_lang));
241 } elseif (strstr($languages,',')) {
242 $languages = explode(',', $languages);
244 $languages = array($languages);
246 if (in_array('zh',$languages) or in_array('ja',$languages)) {
247 // if the current charset != utf-8 the text will not be displayed correctly
248 // but here we cannot change the header anymore. so we can decide to ignore them,
249 // or display them with all the errors.
250 $GLOBALS['charset'] = 'utf-8';
252 $to_lang = $languages[0];
253 if (!empty($string) and count($languages)==1) {
254 return $this->translate($string, $to_lang, $from_lang);
258 if ($dbi->isWikiPage($pagename)) {
260 // google can only translate from english and french
261 if (in_array($from_lang,array('en','fr'))) {
262 $url = "http://translate.google.com/translate";
263 $url .= "?langpair=" . urlencode($from_lang."|".$to_lang);
264 $url .= "&u=" . urlencode(WikiURL($pagename, false, true));
266 // redirect or transclude?
268 return $request->redirect($url);
269 return HTML(fmt("TODO: Google can only translate from english and french. Find a translation service for %s to language %s",
270 WikiURL($pagename, false, true),
273 return $this->error(fmt("%s is empty",$pagename));
276 $pagelist = new PageList('', $exclude, $this->args);
277 $pagelist->_columns[0]->_heading = "$from_lang";
278 foreach ($languages as $lang) {
279 if ($lang == $from_lang) continue;
280 $field = "custom:$lang";
281 $pagelist->addColumnObject(new _PageList_Column_customlang($field, $from_lang, $this));
283 if (!empty($string)) {
284 $pagelist->addPage( $string );
289 $pagelist->addPages( $dbi->getAllPages($include_empty, $sortby, $limit) );
292 // not all pages, only the pgsrc pages
293 if (!is_array($exclude))
294 $exclude = $pagelist->explodePageList($exclude, false, $sortby, $limit);
295 $path = FindLocalizedFile(WIKI_PGSRC);
296 $pgsrc = new fileSet($path);
297 foreach ($pgsrc->getFiles($exclude, $sortby, $limit) as $pagename) {
298 $pagename = urldecode($pagename);
299 if (substr($pagename,-1,1) == '~') continue;
300 if (in_array($pagename, $exclude))
301 continue; // exclude page.
302 if ($match != '*' and !glob_match($match, $pagename))
304 $page_handle = $dbi->getPage($pagename);
305 $pagelist->addPage( $page_handle );
309 if (!isset($this->_locales[$from_lang])) {
310 $this->init_locale($from_lang);
312 $locale = & $this->_locales[$from_lang];
313 if (is_array($locale)) {
315 foreach ($locale as $from => $to) {
316 if ($match != '*' and !glob_match($match, $from))
318 if (isWikiWord($from)) {
320 $pagelist->addPage( $from );
321 if ($limit and $count > $limit) break;
326 // all Button texts, which need a localized .png
327 // where to get them from? templates/*.tmpl: Button() and WikiLink(?,'button')
328 // navbar links, actionpages, and admin requests
330 $buttons = $GLOBALS['AllActionPages'];
331 $fileset = new FileSet(FindFile("themes/MacOSX/buttons/en"), "*.png");
332 foreach ($fileset->getFiles() as $file) {
333 $b = urldecode(substr($file, 0, -4));
334 if (!in_array($b,$buttons))
338 foreach ($buttons as $button) {
339 $pagelist->addPage( $button );
340 if ($limit and ++$count > $limit) break;
348 class _PageList_Column_customlang extends _PageList_Column {
349 function _PageList_Column_customlang($field, $from_lang, $plugin) {
350 $this->_field = $field;
351 $this->_from_lang = $from_lang;
352 $this->_plugin =& $plugin;
353 $this->_what = $plugin->args['what'];
354 $this->_noT = $plugin->args['noT'];
355 $this->_nolinks = $plugin->args['nolinks'];
356 $this->_iscustom = substr($field, 0, 7) == 'custom:';
357 if ($this->_iscustom)
358 $this->_field = substr($field, 7);
360 $this->dbi = &$GLOBALS['request']->getDbh();
361 $this->_PageList_Column_base($this->_field);
364 function _getValue($page, &$revision_handle) {
365 if (is_object($page)) $text = $page->getName();
367 $trans = $this->_plugin->translate($text, $this->_field, $this->_from_lang);
368 // how to markup untranslated words and not existing pages?
369 // untranslated: (TODO) link to translation editor
370 if ($trans == $text or // untranslated
371 (($this->_from_lang != 'en') and
372 ($this->_field != 'en') and
373 ($trans == $this->_plugin->translate($text, 'en', $this->_from_lang))
377 $link = $WikiTheme->linkUnknownWikiWord($trans);
378 if (!($this->_noT or $this->_nolinks) and $this->dbi->isWikiPage($trans)) {
379 $url = WikiURL($trans, array('action' => 'TranslateText','lang' => $this->_field));
380 $button = $WikiTheme->makeButton('T', $url);
381 $button->addTooltip(sprintf(_("Define the translation for %s in %s"), $trans, $this->_field));
382 $link = HTML::span($button);
383 $link->setAttr('class', 'wikiunknown');
384 $text = HTML::span($WikiTheme->maybeSplitWikiWord($trans));
385 $text->setAttr('style', 'text-decoration:line-through');
386 $link->pushContent($text);
388 } elseif (is_object($page))
390 else // not existing: empty
392 } elseif (is_object($page)) {
393 if (!$this->_nolinks)
394 return WikiLink($trans, 'auto');
403 // $Log: not supported by cvs2svn $
404 // Revision 1.13 2004/06/18 14:38:22 rurban
405 // adopt new PageList style
407 // Revision 1.12 2004/06/17 10:39:18 rurban
408 // fix reverse translation of possible actionpage
410 // Revision 1.11 2004/06/14 11:31:39 rurban
411 // renamed global $Theme to $WikiTheme (gforge nameclash)
412 // inherit PageList default options from PageList
413 // default sortby=pagename
414 // use options in PageList_Selectable (limit, sortby, ...)
415 // added action revert, with button at action=diff
416 // added option regex to WikiAdminSearchReplace
418 // Revision 1.10 2004/05/03 21:57:47 rurban
419 // locale updates: we previously lost some words because of wrong strings in
420 // PhotoAlbum, german rewording.
421 // fixed $_SESSION registering (lost session vars, esp. prefs)
422 // fixed ending slash in listAvailableLanguages/Themes
424 // Revision 1.9 2004/05/03 20:44:58 rurban
425 // fixed gettext strings
426 // new SqlResult plugin
427 // _WikiTranslation: fixed init_locale
429 // Revision 1.8 2004/05/02 21:26:38 rurban
430 // limit user session data (HomePageHandle and auth_dbi have to invalidated anyway)
431 // because they will not survive db sessions, if too large.
432 // extended action=upgrade
433 // some WikiTranslation button work
434 // revert WIKIAUTH_UNOBTAINABLE (need it for main.php)
435 // some temp. session debug statements
437 // Revision 1.7 2004/05/02 15:10:08 rurban
438 // new finally reliable way to detect if /index.php is called directly
439 // and if to include lib/main.php
440 // new global AllActionPages
441 // SetupWiki now loads all mandatory pages: HOME_PAGE, action pages, and warns if not.
442 // WikiTranslation what=buttons for Carsten to create the missing MacOSX buttons
443 // PageGroupTestOne => subpages
444 // renamed PhpWikiRss to PhpWikiRecentChanges
445 // more docs, default configs, ...
447 // Revision 1.6 2004/04/21 04:29:50 rurban
448 // write WikiURL consistently (not WikiUrl)
450 // Revision 1.5 2004/03/17 15:38:03 rurban
453 // Revision 1.4 2004/03/17 13:20:31 rurban
454 // Placeholder for all yet untranslated pgsrc pagenames. Add german translations of these.
456 // Revision 1.3 2004/03/16 20:22:32 rurban
457 // added link to TranslateText action
459 // Revision 1.2 2004/03/16 15:47:27 rurban
460 // added match, fixed reverse translation, added page=, what=allpages, what=wikiwords, fixed what=pages, simplified _PageList_Column_custom
462 // Revision 1.1 2004/03/14 16:45:10 rurban
463 // Just the page matrix for now.
464 // doesn't work yet, if the default langauge != en
473 // c-hanging-comment-ender-p: nil
474 // indent-tabs-mode: nil