1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7// 8// TranslationController manages translations of objects (for example translations of a wiki page) 9 10class Services_Language_TranslationController 11{ 12 private $utilities; 13 14 function __construct() 15 { 16 $this->utilities = new Services_Language_Utilities; 17 } 18 19 function setUp() 20 { 21 global $prefs; 22 23 if ($prefs['feature_multilingual'] != 'y') { 24 throw new Services_Exception(tr('Feature Disabled'), 403); 25 } 26 } 27 28 /** 29 * List translations relation of an instance of an object type (eg: translations of a wiki page) 30 * 31 * @param $input 32 * 33 * @return array Array of objects linked together as translations of each other 34 * 35 * @throws Services_Exception 36 */ 37 function action_manage($input) 38 { 39 $type = $input->type->text(); 40 $objectFilter = $this->getObjectFilter($type); 41 42 if (! $objectFilter) { 43 throw new Services_Exception(tr('Translation not supported for the specified object type'), 400); 44 } 45 46 $object = $input->source->$objectFilter(); 47 48 if (! $object) { 49 throw new Services_Exception(tr('No source provided'), 400); 50 } 51 52 return [ 53 'title' => tr('Manage translations'), 54 'type' => $type, 55 'source' => $object, 56 'filters' => $this->getSearchFilters($type, $object), 57 'translations' => $this->utilities->getTranslations($type, $object), 58 'canAttach' => $this->canAttach($type, $object), 59 'canDetach' => $this->canDetach($type, $object), 60 ]; 61 } 62 63 /** 64 * Attach (link) translations for objects (eg: wiki pages) 65 * 66 * @param $input Instances of object types, eg: wiki pages 67 * 68 * @return Forward to utility action to perform the attaching 69 * 70 * @throws Services_Exception 71 */ 72 function action_attach($input) 73 { 74 $type = $input->type->text(); 75 $objectFilter = $this->getObjectFilter($type); 76 77 if (! $objectFilter) { 78 throw new Services_Exception(tr('Translation not supported for the specified object type'), 400); 79 } 80 81 $source = $input->source->$objectFilter(); 82 $target = $input->target->none(); 83 $target = end(explode(':', $target, 2)); 84 $target = TikiFilter::get($objectFilter)->filter($target); 85 86 if (! $source || ! $target) { 87 throw new Services_Exception(tr('No source or target provided'), 400); 88 } 89 90 if (! $this->canAttach($type, $source) || ! $this->canAttach($type, $target)) { 91 throw new Services_Exception(tr('You do not have permission to attach the selected translations'), 403); 92 } 93 94 $succeeded = $this->utilities->insertTranslation($type, $source, $target); 95 96 if (! $succeeded) { 97 throw new Services_Exception(tr('Could not attach the translations.'), 409); 98 } 99 100 return [ 101 'FORWARD' => [ 102 'action' => 'manage', 103 'type' => $type, 104 'source' => $source, 105 ], 106 ]; 107 } 108 109 /** 110 * Detach (unlink) translations for objects (eg: wiki pages) 111 * 112 * @param $input Instances of object types, eg: wiki pages 113 * 114 * @return Forward to utility action to perform the deattaching 115 * 116 * @throws Services_Exception 117 */ 118 function action_detach($input) 119 { 120 $type = $input->type->text(); 121 $objectFilter = $this->getObjectFilter($type); 122 $confirmed = $input->confirm->int(); 123 124 if (! $objectFilter) { 125 throw new Services_Exception(tr('Translation not supported for the specified object type'), 400); 126 } 127 128 $source = $input->source->$objectFilter(); 129 $target = $input->target->$objectFilter(); 130 131 if (! $source || ! $target) { 132 throw new Services_Exception(tr('No source or target provided'), 400); 133 } 134 135 if (! $this->canDetach($type, $source) || ! $this->canDetach($type, $target)) { 136 throw new Services_Exception(tr('You do not have permission to detach the selected translations'), 403); 137 } 138 139 if (! $confirmed) { 140 return [ 141 'title' => tr('Manage translations'), 142 'type' => $type, 143 'source' => $source, 144 'target' => $target, 145 ]; 146 } 147 148 $this->utilities->detachTranslation($type, $source, $target); 149 150 return [ 151 'FORWARD' => [ 152 'action' => 'manage', 153 'type' => $type, 154 'source' => $source, 155 ], 156 ]; 157 } 158 159 /** 160 * Machine translation of an object (eg: a wiki page) 161 * 162 * @param $input An object, eg: a wiki page 163 * 164 * @return action Forward to utility action to perform the attaching 165 */ 166 function action_translate($input) 167 { 168 Services_Exception_Disabled::check('feature_machine_translation'); 169 170 global $prefs; 171 172 $content = $input->content->rawhtml_unsafe(); 173 if (! empty($input->lang->text())) { 174 $lang = $input->lang->text(); 175 } else { 176 $lang = $prefs['language']; 177 } 178 179 $factory = new Multilingual_MachineTranslation; 180 $impl = $factory->getDetectImplementation($lang); 181 182 $content = $impl->translateText($content); 183 184 return [ 185 'content' => $content, 186 'target' => $lang 187 ]; 188 } 189 190 private function getObjectFilter($type) 191 { 192 switch ($type) { 193 case 'wiki page': 194 return 'pagename'; 195 case 'article': 196 case 'trackeritem': 197 return 'int'; 198 } 199 } 200 201 private function getSearchFilters($type, $object) 202 { 203 $translations = $this->utilities->getTranslations($type, $object); 204 $langLib = TikiLib::lib('language'); 205 $languages = $langLib->get_language_map(); 206 207 foreach ($translations as $trans) { 208 unset($languages[$trans['lang']]); 209 } 210 211 unset($languages[$this->utilities->getLanguage($type, $object)]); 212 213 $language = '"' . implode('" OR "', array_keys($languages)) . '"'; 214 if ($language == '""') { 215 $language = null; 216 } 217 218 $filters = [ 219 'type' => $type, 220 'language' => $language, 221 ]; 222 223 if ($type == 'trackeritem') { 224 $info = TikiLib::lib('trk')->get_tracker_item($object); 225 $filters['tracker_id'] = $info['trackerId']; 226 } 227 228 return $filters; 229 } 230 231 /** 232 * Private function to determine if user is allowed to attach (link) translations for objects (eg: wiki pages) 233 * 234 * @param string $type object type, eg: wiki page 235 * @param int $object an instance of object type, eg: a wiki page 236 * 237 * @return 238 */ 239 private function canAttach($type, $object) 240 { 241 global $prefs, $user; 242 $perms = Perms::get($type, $object); 243 244 if ($type == 'wiki page' && $perms->edit) { 245 return true; 246 } 247 248 if ($type == 'article' && $perms->edit_article) { 249 return true; 250 } 251 252 if ($type == 'wiki page' && $prefs['wiki_creator_admin'] == 'y' && $user) { 253 $info = TikiLib::lib('tiki')->get_page_info($object); 254 return $info['creator'] == $user; 255 } 256 257 if ($type == 'article' && $user) { 258 $artlib = TikiLib::lib('art'); 259 $info = $artlib->get_article($object); 260 return $info['author'] == $user && $info['creator_edit'] == 'y'; 261 } 262 263 return $perms->admin; 264 } 265 266 /** 267 * Private function to determine if user is allowed to detach (unlink) translations for objects (eg: wiki pages) 268 * 269 * @param string $type object type, eg: wiki page 270 * @param int $object an instance of object type, eg: a wiki page 271 * 272 * @return 273 */ 274 private function canDetach($type, $object) 275 { 276 $perms = Perms::get($type, $object); 277 return $perms->detach_translation; 278 } 279} 280