Total Complexity | 95 |
Total Lines | 925 |
Duplicated Lines | 0 % |
Changes | 14 | ||
Bugs | 0 | Features | 3 |
Complex classes like Localization_Editor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Localization_Editor, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | class Localization_Editor implements Interface_Optionable |
||
27 | { |
||
28 | use Traits_Optionable; |
||
29 | |||
30 | const MESSAGE_INFO = 'info'; |
||
31 | const MESSAGE_ERROR = 'danger'; |
||
32 | const MESSAGE_WARNING = 'warning'; |
||
33 | const MESSAGE_SUCCESS = 'success'; |
||
34 | |||
35 | const ERROR_NO_SOURCES_AVAILABLE = 40001; |
||
36 | |||
37 | /** |
||
38 | * @var string |
||
39 | */ |
||
40 | protected $installPath; |
||
41 | |||
42 | /** |
||
43 | * @var Localization_Source[] |
||
44 | */ |
||
45 | protected $sources; |
||
46 | |||
47 | /** |
||
48 | * @var \AppUtils\Request |
||
49 | */ |
||
50 | protected $request; |
||
51 | |||
52 | /** |
||
53 | * @var Localization_Source |
||
54 | */ |
||
55 | protected $activeSource; |
||
56 | |||
57 | /** |
||
58 | * @var Localization_Scanner |
||
59 | */ |
||
60 | protected $scanner; |
||
61 | |||
62 | /** |
||
63 | * @var Localization_Locale[] |
||
64 | */ |
||
65 | protected $appLocales = array(); |
||
66 | |||
67 | /** |
||
68 | * @var Localization_Locale |
||
69 | */ |
||
70 | protected $activeAppLocale; |
||
71 | |||
72 | /** |
||
73 | * @var Localization_Editor_Filters |
||
74 | */ |
||
75 | protected $filters; |
||
76 | |||
77 | /** |
||
78 | * @var string[]string |
||
79 | */ |
||
80 | protected $requestParams = array(); |
||
81 | |||
82 | /** |
||
83 | * @var string |
||
84 | */ |
||
85 | protected $varPrefix = 'applocalize_'; |
||
86 | |||
87 | public function __construct() |
||
88 | { |
||
89 | $this->installPath = realpath(__DIR__.'/../'); |
||
90 | $this->request = new Request(); |
||
91 | $this->scanner = Localization::createScanner(); |
||
92 | $this->scanner->load(); |
||
93 | |||
94 | $this->initSession(); |
||
95 | $this->initAppLocales(); |
||
96 | } |
||
97 | |||
98 | public function getRequest() : Request |
||
99 | { |
||
100 | return $this->request; |
||
101 | } |
||
102 | |||
103 | /** |
||
104 | * Adds a request parameter that will be persisted in all URLs |
||
105 | * within the editor. This can be used when integrating the |
||
106 | * editor in an existing page that needs specific request params. |
||
107 | * |
||
108 | * @param string $name |
||
109 | * @param string $value |
||
110 | * @return Localization_Editor |
||
111 | */ |
||
112 | public function addRequestParam(string $name, string $value) : Localization_Editor |
||
113 | { |
||
114 | $this->requestParams[$name] = $value; |
||
115 | return $this; |
||
116 | } |
||
117 | |||
118 | public function getActiveLocale() : Localization_Locale |
||
119 | { |
||
120 | return $this->activeAppLocale; |
||
121 | } |
||
122 | |||
123 | public function getActiveSource() : Localization_Source |
||
124 | { |
||
125 | return $this->activeSource; |
||
126 | } |
||
127 | |||
128 | protected function initSession() |
||
129 | { |
||
130 | if(session_status() != PHP_SESSION_ACTIVE) { |
||
131 | session_start(); |
||
132 | } |
||
133 | |||
134 | if(!isset($_SESSION['localization_messages'])) { |
||
135 | $_SESSION['localization_messages'] = array(); |
||
136 | } |
||
137 | } |
||
138 | |||
139 | public function getVarName($name) |
||
140 | { |
||
141 | return $this->varPrefix.$name; |
||
142 | } |
||
143 | |||
144 | protected function initSources() |
||
145 | { |
||
146 | $this->sources = Localization::getSources(); |
||
147 | |||
148 | if(empty($this->sources)) |
||
149 | { |
||
150 | throw new Localization_Exception( |
||
151 | 'Cannot start editor: no sources defined.', |
||
152 | null, |
||
153 | self::ERROR_NO_SOURCES_AVAILABLE |
||
154 | ); |
||
155 | } |
||
156 | |||
157 | $activeID = $this->request->registerParam($this->getVarName('source'))->setEnum(Localization::getSourceIDs())->get(); |
||
158 | if(empty($activeID)) { |
||
159 | $activeID = $this->getDefaultSourceID(); |
||
160 | } |
||
161 | |||
162 | $this->activeSource = Localization::getSourceByID($activeID); |
||
163 | } |
||
164 | |||
165 | protected function getDefaultSourceID() |
||
166 | { |
||
167 | $default = $this->getOption('default-source'); |
||
168 | if(!empty($default) && Localization::sourceAliasExists($default)) { |
||
169 | return Localization::getSourceByAlias($default)->getID(); |
||
170 | } |
||
171 | |||
172 | return $this->sources[0]->getID(); |
||
173 | } |
||
174 | |||
175 | protected function initAppLocales() |
||
176 | { |
||
177 | $names = array(); |
||
178 | |||
179 | $locales = Localization::getAppLocales(); |
||
180 | foreach($locales as $locale) { |
||
181 | if(!$locale->isNative()) { |
||
182 | $this->appLocales[] = $locale; |
||
183 | $names[] = $locale->getName(); |
||
184 | } |
||
185 | } |
||
186 | |||
187 | // use the default locale if no other is available. |
||
188 | if(empty($names)) { |
||
189 | $this->activeAppLocale = Localization::getAppLocale(); |
||
190 | return; |
||
191 | } |
||
192 | |||
193 | $activeID = $this->request->registerParam($this->getVarName('locale'))->setEnum($names)->get(); |
||
194 | if(empty($activeID)) { |
||
195 | $activeID = $this->appLocales[0]->getName(); |
||
196 | } |
||
197 | |||
198 | $this->activeAppLocale = Localization::getAppLocaleByName($activeID); |
||
199 | |||
200 | Localization::selectAppLocale($activeID); |
||
201 | } |
||
202 | |||
203 | protected function handleActions() |
||
204 | { |
||
205 | $this->initSources(); |
||
206 | |||
207 | $this->filters = new Localization_Editor_Filters($this); |
||
208 | |||
209 | if($this->request->getBool($this->getVarName('scan'))) |
||
210 | { |
||
211 | $this->executeScan(); |
||
212 | } |
||
213 | else if($this->request->getBool($this->getVarName('save'))) |
||
214 | { |
||
215 | $this->executeSave(); |
||
216 | } |
||
217 | } |
||
218 | |||
219 | public function getScanner() : Localization_Scanner |
||
220 | { |
||
221 | return $this->scanner; |
||
222 | } |
||
223 | |||
224 | public function render() |
||
225 | { |
||
226 | $this->handleActions(); |
||
227 | |||
228 | $appName = $this->getAppName(); |
||
229 | |||
230 | ob_start(); |
||
231 | |||
232 | ?><!doctype html> |
||
233 | <html lang="en"> |
||
234 | <head> |
||
235 | <meta charset="utf-8"> |
||
236 | <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||
237 | <meta name="description" content=""> |
||
238 | <title><?php echo $appName ?></title> |
||
239 | <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> |
||
240 | <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> |
||
241 | <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> |
||
242 | <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> |
||
243 | <script src="https://kit.fontawesome.com/54212b9b2b.js" crossorigin="anonymous"></script> |
||
244 | <script><?php echo $this->getJavascript() ?></script> |
||
245 | <style><?php echo $this->getCSS() ?></style> |
||
246 | </head> |
||
247 | <body> |
||
248 | <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top"> |
||
249 | <a class="navbar-brand" href="<?php echo $this->getURL() ?>"><?php echo $appName ?></a> |
||
250 | <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation"> |
||
251 | <span class="navbar-toggler-icon"></span> |
||
252 | </button> |
||
253 | |||
254 | <div class="collapse navbar-collapse" id="navbarsExampleDefault"> |
||
255 | <?php |
||
256 | if(!empty($this->appLocales)) |
||
257 | { |
||
258 | ?> |
||
259 | <ul class="navbar-nav mr-auto"> |
||
260 | <li class="nav-item dropdown"> |
||
261 | <a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
||
262 | <?php pt('Text sources') ?> |
||
263 | </a> |
||
264 | <div class="dropdown-menu" aria-labelledby="dropdown01"> |
||
265 | <?php |
||
266 | foreach($this->sources as $source) |
||
267 | { |
||
268 | ?> |
||
269 | <a class="dropdown-item" href="<?php echo $this->getSourceURL($source) ?>"> |
||
270 | <?php |
||
271 | if($source->getID() === $this->activeSource->getID()) |
||
272 | { |
||
273 | ?> |
||
274 | <b><?php echo $source->getLabel() ?></b> |
||
275 | <?php |
||
276 | } |
||
277 | else |
||
278 | { |
||
279 | echo $source->getLabel(); |
||
280 | } |
||
281 | ?> |
||
282 | <?php |
||
283 | $untranslated = $source->countUntranslated($this->scanner); |
||
284 | if($untranslated > 0) { |
||
285 | ?> |
||
286 | (<span class="text-danger" title="<?php pt('%1$s texts have not been translated in this text source.', $untranslated) ?>"><?php echo $untranslated ?></span>) |
||
287 | <?php |
||
288 | } |
||
289 | ?> |
||
290 | </a> |
||
291 | <?php |
||
292 | } |
||
293 | ?> |
||
294 | </div> |
||
295 | </li> |
||
296 | <li class="nav-item dropdown"> |
||
297 | <a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
||
298 | <?php echo $this->activeAppLocale->getLabel() ?> |
||
299 | </a> |
||
300 | <div class="dropdown-menu" aria-labelledby="dropdown01"> |
||
301 | <?php |
||
302 | foreach($this->appLocales as $locale) |
||
303 | { |
||
304 | ?> |
||
305 | <a class="dropdown-item" href="<?php echo $this->getLocaleURL($locale) ?>"> |
||
306 | <?php echo $locale->getLabel() ?> |
||
307 | </a> |
||
308 | <?php |
||
309 | } |
||
310 | ?> |
||
311 | </div> |
||
312 | </li> |
||
313 | <li class="nav-item"> |
||
314 | <a href="<?php echo $this->getScanURL() ?>" class="btn btn-light btn-sm" title="<?php pt('Scan all source files to find translateable texts.') ?>" data-toggle="tooltip"> |
||
315 | <i class="fa fa-refresh"></i> |
||
316 | <?php pt('Scan') ?> |
||
317 | </a> |
||
318 | </li> |
||
319 | <?php |
||
320 | if($this->scanner->hasWarnings()) { |
||
321 | ?> |
||
322 | <li class="nav-item"> |
||
323 | <a href="<?php echo $this->getWarningsURL() ?>"> |
||
324 | <span class="badge badge-warning" title="<?php pts('The last scan for translateable texts reported warnings.'); pts('Click for details.'); ?>" data-toggle="tooltip"> |
||
325 | <i class="fa fa-exclamation-triangle"></i> |
||
326 | <?php echo $this->scanner->countWarnings() ?> |
||
327 | </span> |
||
328 | </a> |
||
329 | </li> |
||
330 | <?php |
||
331 | } |
||
332 | ?> |
||
333 | </ul> |
||
334 | <?php |
||
335 | } |
||
336 | ?> |
||
337 | <?php |
||
338 | $backURL = $this->getOption('back-url'); |
||
339 | if(!empty($backURL)) |
||
340 | { |
||
341 | ?> |
||
342 | <a href="<?php echo $backURL ?>" class="btn btn-light btn-sm"> |
||
343 | <i class="fas fa-arrow-circle-left"></i> |
||
344 | <?php echo $this->getOption('back-label'); ?> |
||
345 | </a> |
||
346 | <?php |
||
347 | } |
||
348 | ?> |
||
349 | </div> |
||
350 | </nav> |
||
351 | <main role="main" class="container"> |
||
352 | <div> |
||
353 | <?php |
||
354 | if(empty($this->appLocales)) |
||
355 | { |
||
356 | ?> |
||
357 | <div class="alert alert-danger"> |
||
358 | <i class="fa fa-exclamation-triangle"></i> |
||
359 | <b><?php pt('Nothing to translate:') ?></b> |
||
360 | <?php pt('No application locales were added to translate to.') ?> |
||
361 | </div> |
||
362 | <?php |
||
363 | } |
||
364 | else if($this->request->getBool($this->getVarName('warnings'))) |
||
365 | { |
||
366 | echo $this->renderWarnings(); |
||
367 | } |
||
368 | else |
||
369 | { |
||
370 | ?> |
||
371 | <h1><?php echo $this->activeSource->getLabel() ?></h1> |
||
372 | <?php |
||
373 | if(!empty($_SESSION['localization_messages'])) |
||
374 | { |
||
375 | foreach($_SESSION['localization_messages'] as $def) |
||
376 | { |
||
377 | ?> |
||
378 | <div class="alert alert-<?php echo $def['type'] ?>" role="alert"> |
||
379 | <?php echo $def['text'] ?> |
||
380 | <button type="button" class="close" data-dismiss="alert" aria-label="<?php pt('Close') ?>" title="<?php pt('Dismiss this message.') ?>" data-toggle="tooltip"> |
||
381 | <span aria-hidden="true">×</span> |
||
382 | </button> |
||
383 | </div> |
||
384 | <?php |
||
385 | } |
||
386 | |||
387 | // reset the messages after having displayed them |
||
388 | $_SESSION['localization_messages'] = array(); |
||
389 | } |
||
390 | ?> |
||
391 | <p> |
||
392 | <?php |
||
393 | pt( |
||
394 | 'You are translating to %1$s', |
||
395 | '<span class="badge badge-info">'. |
||
396 | $this->activeAppLocale->getLabel(). |
||
397 | '</span>' |
||
398 | ); |
||
399 | ?><br> |
||
400 | <?php pt('Found %1$s texts to translate.', $this->activeSource->countUntranslated($this->scanner)) ?> |
||
401 | </p> |
||
402 | <br> |
||
403 | <?php |
||
404 | if(!$this->scanner->isScanAvailable()) |
||
405 | { |
||
406 | ?> |
||
407 | <div class="alert alert-primary" role="alert"> |
||
408 | <b><?php pt('No texts found:') ?></b> |
||
409 | <?php pt('The source folders have not been scanned yet.') ?> |
||
410 | </div> |
||
411 | <p> |
||
412 | <a href="<?php echo $this->getScanURL() ?>" class="btn btn-primary"> |
||
413 | <i class="fa fa-refresh"></i> |
||
414 | <?php pt('Scan files now') ?> |
||
415 | </a> |
||
416 | </p> |
||
417 | <?php |
||
418 | } |
||
419 | else |
||
420 | { |
||
421 | echo $this->filters->renderForm(); |
||
422 | echo $this->renderList(); |
||
|
|||
423 | } |
||
424 | |||
425 | } |
||
426 | ?> |
||
427 | </div> |
||
428 | </main> |
||
429 | </body> |
||
430 | </html> |
||
431 | <?php |
||
432 | |||
433 | return ob_get_clean(); |
||
434 | } |
||
435 | |||
436 | protected function renderWarnings() |
||
437 | { |
||
438 | ob_start(); |
||
439 | |||
440 | ?> |
||
441 | <h1><?php pt('Warnings') ?></h1> |
||
442 | <p class="abstract"> |
||
443 | <?php |
||
444 | pts('The following shows all texts where the system decided that they cannot be translated.'); |
||
445 | ?> |
||
446 | </p> |
||
447 | <dl> |
||
448 | <?php |
||
449 | $warnings = $this->scanner->getWarnings(); |
||
450 | |||
451 | foreach($warnings as $warning) |
||
452 | { |
||
453 | ?> |
||
454 | <dt><?php echo FileHelper::relativizePathByDepth($warning->getFile(), 3) ?>:<?php echo $warning->getLine() ?></dt> |
||
455 | <dd><?php echo $warning->getMessage() ?></dd> |
||
456 | <?php |
||
457 | } |
||
458 | |||
459 | ?> |
||
460 | </dl> |
||
461 | <?php |
||
462 | |||
463 | return ob_get_clean(); |
||
464 | } |
||
465 | |||
466 | protected function getFilteredStrings() |
||
467 | { |
||
468 | $strings = $this->activeSource->getHashes($this->scanner); |
||
469 | |||
470 | $result = array(); |
||
471 | |||
472 | foreach($strings as $string) |
||
473 | { |
||
474 | if($this->filters->isStringMatch($string)) { |
||
475 | $result[] = $string; |
||
476 | } |
||
477 | } |
||
478 | |||
479 | return $result; |
||
480 | } |
||
481 | |||
482 | public function getRequestParams() : array |
||
483 | { |
||
484 | $params = $this->requestParams; |
||
485 | $params[$this->getVarName('locale')] = $this->activeAppLocale->getName(); |
||
486 | $params[$this->getVarName('source')] = $this->activeSource->getID(); |
||
487 | $params[$this->getVarName('page')] = $this->getPage(); |
||
488 | |||
489 | return $params; |
||
490 | } |
||
491 | |||
492 | protected function getPage() : int |
||
493 | { |
||
494 | return intval($this->request |
||
495 | ->registerParam($this->getVarName('page')) |
||
496 | ->setInteger() |
||
497 | ->get(0) |
||
498 | ); |
||
499 | } |
||
500 | |||
501 | protected $perPage = 20; |
||
502 | |||
503 | protected function renderList() |
||
504 | { |
||
505 | $strings = $this->getFilteredStrings(); |
||
506 | |||
507 | if(empty($strings)) |
||
508 | { |
||
509 | ?> |
||
510 | <div class="alert alert-info"> |
||
511 | <?php pt('No matching strings found.') ?> |
||
512 | </div> |
||
513 | <?php |
||
514 | |||
515 | return; |
||
516 | } |
||
517 | |||
518 | $total = count($strings); |
||
519 | $page = $this->getPage(); |
||
520 | $pager = new \AppUtils\PaginationHelper($total, $this->perPage, $page); |
||
521 | |||
522 | $keep = array_slice($strings, $pager->getOffsetStart(), $this->perPage); |
||
523 | |||
524 | ?> |
||
525 | <form method="post"> |
||
526 | <div class="form-hiddens"> |
||
527 | <?php |
||
528 | $params = $this->getRequestParams(); |
||
529 | foreach($params as $name => $value) { |
||
530 | ?> |
||
531 | <input type="hidden" name="<?php echo $name ?>" value="<?php echo $value ?>"> |
||
532 | <?php |
||
533 | } |
||
534 | ?> |
||
535 | </div> |
||
536 | <table class="table table-hover"> |
||
537 | <thead> |
||
538 | <tr> |
||
539 | <th><?php pt('Text') ?></th> |
||
540 | <th class="align-center"><?php pt('Translated?') ?></th> |
||
541 | <th class="align-center"><?php pt('Location') ?></th> |
||
542 | <th class="align-right"><?php pt('Sources') ?></th> |
||
543 | </tr> |
||
544 | </thead> |
||
545 | <tbody> |
||
546 | <?php |
||
547 | foreach($keep as $string) |
||
548 | { |
||
549 | $this->renderListEntry($string); |
||
550 | } |
||
551 | ?> |
||
552 | </tbody> |
||
553 | </table> |
||
554 | <?php |
||
555 | if($pager->hasPages()) |
||
556 | { |
||
557 | $prevUrl = $this->getPaginationURL($pager->getPreviousPage()); |
||
558 | $nextUrl = $this->getPaginationURL($pager->getNextPage()); |
||
559 | |||
560 | ?> |
||
561 | <nav aria-label="<?php pt('Navigate available pages of texts.') ?>"> |
||
562 | <ul class="pagination"> |
||
563 | <li class="page-item"> |
||
564 | <a class="page-link" href="<?php echo $prevUrl ?>"> |
||
565 | <i class="fa fa-arrow-left"></i> |
||
566 | </a> |
||
567 | </li> |
||
568 | <?php |
||
569 | $numbers = $pager->getPageNumbers(); |
||
570 | foreach($numbers as $number) |
||
571 | { |
||
572 | $url = $this->getPaginationURL($number); |
||
573 | |||
574 | ?> |
||
575 | <li class="page-item <?php if($pager->isCurrentPage($number)) { echo 'active'; } ?>"> |
||
576 | <a class="page-link" href="<?php echo $url ?>"> |
||
577 | <?php echo $number ?> |
||
578 | </a> |
||
579 | </li> |
||
580 | <?php |
||
581 | } |
||
582 | ?> |
||
583 | <li class="page-item"> |
||
584 | <a class="page-link" href="<?php echo $nextUrl ?>"> |
||
585 | <i class="fa fa-arrow-right"></i> |
||
586 | </a> |
||
587 | </li> |
||
588 | </ul> |
||
589 | </nav> |
||
590 | <?php |
||
591 | } |
||
592 | ?> |
||
593 | <br> |
||
594 | <p> |
||
595 | <button type="submit" name="<?php echo $this->getVarName('save') ?>" value="yes" class="btn btn-primary"> |
||
596 | <i class="fas fa-save"></i> |
||
597 | <?php pt('Save now') ?> |
||
598 | </button> |
||
599 | </p> |
||
600 | </form> |
||
601 | |||
602 | <?php |
||
603 | } |
||
604 | |||
605 | protected function getPaginationURL(int $page, $params=array()) |
||
610 | } |
||
611 | |||
612 | protected function renderListEntry(Localization_Scanner_StringHash $string) |
||
613 | { |
||
614 | $hash = $string->getHash(); |
||
615 | |||
616 | $previewText = $string->getTranslatedText(); |
||
617 | if(empty($previewText)) { |
||
618 | $previewText = $string->getText(); |
||
619 | } |
||
620 | |||
621 | $shortText = $this->renderText($previewText, 50); |
||
622 | |||
623 | $files = $string->getFiles(); |
||
624 | |||
625 | ?> |
||
626 | <tr class="string-entry inactive" onclick="Editor.Toggle('<?php echo $hash ?>')" data-hash="<?php echo $hash ?>"> |
||
627 | <td class="string-text"><?php echo $shortText ?></td> |
||
628 | <td class="align-center string-status"><?php echo $this->renderStatus($string) ?></td> |
||
629 | <td class="align-center"><?php echo $this->renderTypes($string) ?></td> |
||
630 | <td class="align-right"><?php echo $this->renderFileNames($string) ?></td> |
||
631 | </tr> |
||
632 | <tr class="string-form"> |
||
633 | <td colspan="4"> |
||
634 | <?php echo pt('Native text:') ?> |
||
635 | <p class="native-text"><?php echo $this->renderText($string->getText()) ?></p> |
||
636 | <p> |
||
637 | <textarea rows="4" class="form-control" name="<?php echo $this->getVarName('strings') ?>[<?php echo $hash ?>]"><?php echo $string->getTranslatedText() ?></textarea> |
||
638 | </p> |
||
639 | <p> |
||
640 | <button type="button" class="btn btn-outline-primary btn-sm" onclick="Editor.Confirm('<?php echo $hash ?>')"> |
||
641 | <?php pt('OK') ?> |
||
642 | </button> |
||
643 | <button type="button" class="btn btn-outline-secondary btn-sm" onclick="Editor.Toggle('<?php echo $hash ?>')"> |
||
644 | <?php pt('Cancel') ?> |
||
645 | </button> |
||
646 | </p> |
||
647 | <div class="files-list"> |
||
648 | <p> |
||
649 | <?php |
||
650 | $totalFiles = count($files); |
||
651 | |||
652 | if($totalFiles == 1) |
||
653 | { |
||
654 | pt('Found in a single file:'); |
||
655 | } |
||
656 | else |
||
657 | { |
||
658 | pt('Found in %1$s files:', $totalFiles); |
||
659 | } |
||
660 | ?> |
||
661 | </p> |
||
662 | <div class="files-scroller"> |
||
663 | <ul> |
||
664 | <?php |
||
665 | $locations = $string->getStrings(); |
||
666 | |||
667 | foreach($locations as $location) |
||
668 | { |
||
669 | $file = $location->getSourceFile(); |
||
670 | $line = $location->getLine(); |
||
671 | |||
672 | $icon = ''; |
||
673 | |||
674 | $ext = \AppUtils\FileHelper::getExtension($file); |
||
675 | |||
676 | if($ext == 'php') { |
||
677 | $icon = 'fab fa-php'; |
||
678 | } else if($ext == 'js') { |
||
679 | $icon = 'fab fa-js-square'; |
||
680 | } else { |
||
681 | $icon = 'fas fa-file-code'; |
||
682 | } |
||
683 | |||
684 | ?> |
||
685 | <li> |
||
686 | <i class="<?php echo $icon ?>"></i> |
||
687 | <?php echo $file ?><span class="line-number">:<?php echo $line ?></span> |
||
688 | </li> |
||
689 | <?php |
||
690 | } |
||
691 | ?> |
||
692 | </ul> |
||
693 | </div> |
||
694 | </div> |
||
695 | </td> |
||
696 | </tr> |
||
697 | <?php |
||
698 | |||
699 | } |
||
700 | |||
701 | protected function renderText(string $text, int $cutAt=0) : string |
||
702 | { |
||
703 | if(empty($text)) { |
||
704 | return $text; |
||
705 | } |
||
706 | |||
707 | if($cutAt > 0) { |
||
708 | $text = \AppUtils\ConvertHelper::text_cut($text, $cutAt); |
||
709 | } |
||
710 | |||
711 | $text = htmlspecialchars($text); |
||
712 | |||
713 | $vars = $this->detectVariables($text); |
||
714 | |||
715 | foreach($vars as $var) { |
||
716 | $text = str_replace($var, '<span class="placeholder">'.$var.'</span>', $text); |
||
717 | } |
||
718 | |||
719 | return $text; |
||
720 | } |
||
721 | |||
722 | protected function detectVariables(string $string) : array |
||
723 | { |
||
724 | $result = array(); |
||
725 | preg_match_all('/%[0-9]+d|%s|%[0-9]+\$s/i', $string, $result, PREG_PATTERN_ORDER); |
||
726 | |||
727 | if(isset($result[0]) && !empty($result[0])) { |
||
728 | return $result[0]; |
||
729 | } |
||
730 | |||
731 | return array(); |
||
732 | } |
||
733 | |||
734 | protected function renderFileNames(Localization_Scanner_StringHash $hash) : string |
||
735 | { |
||
736 | $max = 2; |
||
737 | $total = $hash->countFiles(); |
||
738 | $keep = $hash->getFileNames(); |
||
739 | $keepTotal = count($keep); // with duplicate file names, this can be less than the file total |
||
740 | |||
741 | // add a counter of the additional files if the total |
||
742 | // is higher than the maximum to show |
||
743 | if($total > $max) |
||
744 | { |
||
745 | $length = $max; |
||
746 | if($length > $keepTotal) { |
||
747 | $length = $keepTotal; |
||
748 | } |
||
749 | |||
750 | $keep = array_slice($keep, 0, $length); |
||
751 | $keep[] = '+'.($total - $length); |
||
752 | } |
||
753 | |||
754 | $result = implode(', ', $keep); |
||
755 | |||
756 | return $result; |
||
757 | } |
||
758 | |||
759 | public function display() |
||
760 | { |
||
761 | echo $this->render(); |
||
762 | } |
||
763 | |||
764 | protected function getJavascript() : string |
||
765 | { |
||
766 | return file_get_contents($this->installPath.'/js/editor.js'); |
||
767 | } |
||
768 | |||
769 | protected function getCSS() : string |
||
770 | { |
||
771 | return file_get_contents($this->installPath.'/css/editor.css'); |
||
772 | } |
||
773 | |||
774 | public function getSourceURL(Localization_Source $source, array $params=array()) |
||
775 | { |
||
776 | $params[$this->getVarName('source')] = $source->getID(); |
||
777 | |||
778 | return $this->getURL($params); |
||
779 | } |
||
780 | |||
781 | public function getLocaleURL(Localization_Locale $locale, array $params=array()) |
||
782 | { |
||
783 | $params[$this->getVarName('locale')] = $locale->getName(); |
||
784 | |||
785 | return $this->getURL($params); |
||
786 | } |
||
787 | |||
788 | public function getScanURL() |
||
789 | { |
||
790 | return $this->getSourceURL($this->activeSource, array($this->getVarName('scan') => 'yes')); |
||
791 | } |
||
792 | |||
793 | public function getWarningsURL() |
||
794 | { |
||
795 | return $this->getSourceURL($this->activeSource, array($this->getVarName('warnings') => 'yes')); |
||
796 | } |
||
797 | |||
798 | public function getURL(array $params=array()) |
||
799 | { |
||
800 | $persist = $this->getRequestParams(); |
||
801 | |||
802 | foreach($persist as $name => $value) { |
||
803 | if(!isset($params[$name])) { |
||
804 | $params[$name] = $value; |
||
805 | } |
||
806 | } |
||
807 | |||
808 | return '?'.http_build_query($params); |
||
809 | } |
||
810 | |||
811 | public function redirect($url) |
||
812 | { |
||
813 | header('Location:'.$url); |
||
814 | exit; |
||
815 | } |
||
816 | |||
817 | protected function executeScan() |
||
818 | { |
||
819 | $this->scanner->scan(); |
||
820 | |||
821 | $this->addMessage( |
||
822 | t('The source files have been analyzed successfully at %1$s.', date('H:i:s')), |
||
823 | self::MESSAGE_SUCCESS |
||
824 | ); |
||
825 | |||
826 | $this->redirect($this->getSourceURL($this->activeSource)); |
||
827 | } |
||
828 | |||
829 | protected function executeSave() |
||
830 | { |
||
831 | $data = $_POST; |
||
832 | |||
833 | $translator = Localization::getTranslator($this->activeAppLocale); |
||
834 | |||
835 | $strings = $data[$this->getVarName('strings')]; |
||
836 | foreach($strings as $hash => $text) |
||
837 | { |
||
838 | $text = trim($text); |
||
839 | |||
840 | if(empty($text)) { |
||
841 | continue; |
||
842 | } |
||
843 | |||
844 | $translator->setTranslation($hash, $text); |
||
845 | } |
||
846 | |||
847 | $translator->save($this->activeSource, $this->scanner->getCollection()); |
||
848 | |||
849 | // refresh all the client files |
||
850 | Localization::writeClientFiles(true); |
||
851 | |||
852 | $this->addMessage( |
||
853 | t('The texts have been updated successfully at %1$s.', date('H:i:s')), |
||
854 | self::MESSAGE_SUCCESS |
||
855 | ); |
||
856 | |||
857 | $this->redirect($this->getURL()); |
||
858 | } |
||
859 | |||
860 | protected function renderStatus(Localization_Scanner_StringHash $hash) |
||
861 | { |
||
862 | if($hash->isTranslated()) { |
||
863 | return '<i class="fa fa-check text-success"></i>'; |
||
864 | } |
||
865 | |||
866 | return '<i class="fa fa-ban text-danger"></i>'; |
||
867 | } |
||
868 | |||
869 | protected function renderTypes(Localization_Scanner_StringHash $hash) |
||
870 | { |
||
871 | $types = array(); |
||
872 | |||
873 | if($hash->hasLanguageType('PHP')) { |
||
874 | $types[] = t('Server'); |
||
875 | } |
||
876 | |||
877 | if($hash->hasLanguageType('Javascript')) { |
||
878 | $types[] = t('Client'); |
||
879 | } |
||
880 | |||
881 | return implode(', ', $types); |
||
882 | } |
||
883 | |||
884 | protected function addMessage($message, $type=self::MESSAGE_INFO) |
||
889 | ); |
||
890 | } |
||
891 | |||
892 | public function getDefaultOptions() : array |
||
893 | { |
||
894 | return array( |
||
895 | 'appname' => '', |
||
896 | 'default-source' => '', |
||
897 | 'back-url' => '', |
||
898 | 'back-label' => '' |
||
899 | ); |
||
900 | } |
||
901 | |||
902 | /** |
||
903 | * Sets the application name shown in the main navigation |
||
904 | * in the user interface. |
||
905 | * |
||
906 | * @param string $name |
||
907 | * @return Localization_Editor |
||
908 | */ |
||
909 | public function setAppName(string $name) : Localization_Editor |
||
910 | { |
||
911 | $this->setOption('appname', $name); |
||
912 | return $this; |
||
913 | } |
||
914 | |||
915 | public function getAppName() : string |
||
916 | { |
||
917 | $name = $this->getOption('appname'); |
||
918 | if(!empty($name)) { |
||
919 | return $name; |
||
920 | } |
||
921 | |||
922 | return t('Localization editor'); |
||
923 | } |
||
924 | |||
925 | /** |
||
926 | * Selects the default source to use if none has been |
||
927 | * explicitly selected. |
||
928 | * |
||
929 | * @param string $sourceID |
||
930 | */ |
||
931 | public function selectDefaultSource(string $sourceID) : Localization_Editor |
||
932 | { |
||
933 | $this->setOption('default-source', $sourceID); |
||
934 | return $this; |
||
935 | } |
||
936 | |||
937 | /** |
||
938 | * Sets an URL that the translators can use to go back to |
||
939 | * the main application, for example if it is integrated into |
||
940 | * an existing application. |
||
941 | * |
||
942 | * @param string $url The URL to use for the link |
||
943 | * @param string $label Label of the link |
||
944 | * @return Localization_Editor |
||
945 | */ |
||
946 | public function setBackURL(string $url, string $label) : Localization_Editor |
||
951 | } |
||
952 | } |
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.