1<?php
2
3// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
4//
5// All Rights Reserved. See copyright.txt for details and a complete list of authors.
6// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
7// $Id$
8
9namespace Tiki\Command;
10
11use Language_CollectFiles;
12use Language_FileType_Php;
13use Language_FileType_Tpl;
14use Language_GetStrings;
15use Language_WriteFile_Factory;
16use Symfony\Component\Console\Command\Command;
17use Symfony\Component\Console\Helper\ProgressBar;
18use Symfony\Component\Console\Input\InputInterface;
19use Symfony\Component\Console\Output\OutputInterface;
20use Symfony\Component\Console\Input\InputOption;
21use timer;
22
23/**
24 * @package Tiki\Command
25 *
26 * Update lang/xx/language.php files
27 *
28 * Scans a directory (its files) and a set of (individual) files
29 * By default, the directory scanned is the Tiki root, excluding $excludeDirs. By default, the individual files scanned are files in these otherwise excluded directories.
30 *
31 * Examples:
32 * 		- http://localhost/pathToTiki/get_strings.php -> update all language.php files
33 * 		- http://localhost/pathToTiki/get_strings.php?lang=fr -> update just lang/fr/language.php file
34 * 		- http://localhost/pathToTiki/get_strings.php?lang[]=fr&lang[]=pt-br&outputFiles -> update both French
35 * 		  and Brazilian Portuguese language.php files and for each string add a line with
36 * 		  the file where it was found.
37 *
38 * Command line examples:
39 * 		- php get_strings.php
40 * 		- php get_strings.php lang=pt-br outputFiles=true
41 *
42 * 		Only scan lib/, and only part of lib/ (exclude lib/core/Zend and lib/captcha), but still include captchalib.php and index.php
43 * 		This FAILS as of 2017-09-15, since the language files (for output) are looked for in baseDir.
44 * 		- php get_strings.php baseDir=lib/ excludeDirs=lib/core/Zend,lib/captcha includeFiles=captchalib.php,index.php fileName=language_r.php
45 *
46 *
47 */
48
49class GetStringsCommand extends Command
50{
51	protected function configure(): void
52	{
53		$this
54			->setName('translation:getstrings')
55			->setDescription('Update language.php files with new strings')
56			->setHelp('Scans all Tiki files and adds new English strings to language files. Also reorganizes existing strings.')
57			->addOption(
58				'lang',
59				'l',
60				InputOption::VALUE_OPTIONAL,
61				'Language code to process eg. lang=pt-br'
62			)
63			->addOption(
64				'outputfiles',
65				null,
66				InputOption::VALUE_NONE,
67				'For each string add a line with the file where it was found'
68			)
69			->addOption(
70				'exclude',
71				null,
72				InputOption::VALUE_OPTIONAL,
73				'Directories that should be excluded from searching'
74			)
75			->addOption(
76				'include',
77				null,
78				InputOption::VALUE_OPTIONAL,
79				'Individual files that should be included in otherwise excluded directories'
80			)
81			->addOption(
82				'basedir',
83				null,
84				InputOption::VALUE_OPTIONAL,
85				'The base directory to use. Will invalidate default exclude and include parameters'
86			)
87			->addOption(
88				'filename',
89				null,
90				InputOption::VALUE_OPTIONAL,
91				'eg. filename=language_r.php'
92			);
93	}
94
95	protected function execute(InputInterface $input, OutputInterface $output): void
96	{
97		$timer = new timer();
98		$timer->start();
99
100		$options = [];
101		$options['lang'] = $input->getOption('lang') ?: null;
102		$options['outputFiles'] = $input->getOption('outputfiles') ?: null;
103		$excludeDirs = ['dump', 'img', 'lang', 'bin', 'installer/schema', 'vendor_bundled', 'vendor', 'vendor_extra', 'vendor_custom', 'lib/test', 'temp', 'permissioncheck', 'storage', 'tiki_tests',
104						'doc', 'db', 'lib/openlayers', 'tests', 'modules/cache'];
105		$excludeDirs = array_filter($excludeDirs, 'is_dir'); // only keep in the exclude list if the dir exists
106
107		// Files are processed after the base directory, so adding a file here allows to scan it even if its directory was excluded.
108		$includeFiles = ['./lang/langmapping.php', './img/flags/flagnames.php'];
109
110		if ($input->getOption('basedir')) {
111			$options['baseDir'] = $input->getOption('basedir');
112
113			// when a custom base dir is set, default $includeFiles and $excludeDirs are not used
114			$includeFiles = [];
115			$excludeDirs = [];
116		}
117		if ($input->getOption('exclude')) {
118			$excludeDirs = explode(',', $input->getOption('exclude'));
119		}
120		if ($input->getOption('include')) {
121			$includeFiles = explode(',', $input->getOption('include'));
122		}
123		$options['fileName'] = $input->getOption('filename') ?: null;
124
125		$getStrings = new Language_GetStrings(new Language_CollectFiles, new Language_WriteFile_Factory, $options);
126
127		$getStrings->addFileType(new Language_FileType_Php);
128		$getStrings->addFileType(new Language_FileType_Tpl);
129
130		// skip the following directories
131		$getStrings->collectFiles->setExcludeDirs($excludeDirs);
132
133		// manually add the following files from skipped directories
134		$getStrings->collectFiles->setIncludeFiles($includeFiles);
135
136		$langs = $getStrings->getLanguages();
137		sort($langs);
138		$output->writeln(count($langs) . ' Languages: ' . implode(' ', $langs));
139
140		$getStrings->run();
141
142		$output->writeln('Total time spent: ' . $timer->stop() . ' seconds');
143		$output->writeln('<comment>You may now review and commit</comment>');
144		$output->writeln(
145			'<info>Warning: Committing the results of getstrings will prevent identifying broken strings with translation:englishupdate so englishupdate should be run first to prevent gradual translation loss. See englishupdate help for details.</info>'
146		);
147	}
148}
149