Passed
Pull Request — master (#81)
by Dante
01:03
created

GettextCommand::ttagExtract()   B

Complexity

Conditions 10
Paths 37

Size

Total Lines 35
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 10
eloc 18
c 2
b 1
f 0
nc 37
nop 2
dl 0
loc 35
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * BEdita, API-first content management framework
6
 * Copyright 2022 Atlas Srl, Chialab Srl
7
 *
8
 * This file is part of BEdita: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published
10
 * by the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
14
 */
15
16
namespace BEdita\I18n\Command;
17
18
use BEdita\I18n\Filesystem\File;
19
use BEdita\I18n\Filesystem\Gettext;
20
use BEdita\I18n\Filesystem\Paths;
21
use BEdita\I18n\Filesystem\Ttag;
22
use Cake\Command\Command;
23
use Cake\Console\Arguments;
24
use Cake\Console\ConsoleIo;
25
use Cake\Console\ConsoleOptionParser;
26
use Cake\Core\Configure;
27
use Cake\Utility\Hash;
28
29
/**
30
 * Gettext command.
31
 */
32
class GettextCommand extends Command
33
{
34
    /**
35
     * @var int
36
     */
37
    public const CODE_CHANGES = 2;
38
39
    /**
40
     * The Po results
41
     *
42
     * @var array
43
     */
44
    protected $poResult = [];
45
46
    /**
47
     * The template paths
48
     *
49
     * @var array
50
     */
51
    protected $templatePaths = [];
52
53
    /**
54
     * The locale path
55
     *
56
     * @var string
57
     */
58
    protected $localePath = '';
59
60
    /**
61
     * The name of default domain if not specified. Used for pot and po file names.
62
     *
63
     * @var string
64
     */
65
    protected $defaultDomain = 'default';
66
67
    /**
68
     * The locales to generate.
69
     *
70
     * @var array
71
     */
72
    protected $locales = [];
73
74
    /**
75
     * @inheritDoc
76
     */
77
    public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser
78
    {
79
        return parent::buildOptionParser($parser)
80
            ->setDescription([
81
                'Create or update i18n po/pot files',
82
                '',
83
                '`bin/cake gettext`: update files for current app',
84
                '`bin/cake gettext -app <app path>`: update files for the app',
85
                '`bin/cake gettext -plugin <plugin name>`: update files for the plugin',
86
            ])
87
            ->addOption('app', [
88
                'help' => 'The app path, for i18n update.',
89
                'short' => 'a',
90
                'required' => false,
91
            ])
92
            ->addOption('plugin', [
93
                'help' => 'The plugin name, for i18n update.',
94
                'short' => 'p',
95
                'required' => false,
96
            ])
97
            ->addOption('plugins', [
98
                'help' => 'All plugins',
99
                'required' => false,
100
                'boolean' => true,
101
            ])
102
            ->addOption('ci', [
103
                'help' => 'Run in CI mode. Exit with error if PO files are changed.',
104
                'required' => false,
105
                'boolean' => true,
106
            ])
107
            ->addOption('locales', [
108
                'help' => 'Comma separated list of locales to generate. Leave empty to use configuration `I18n.locales`',
109
                'short' => 'l',
110
                'default' => implode(',', array_keys((array)Configure::read('I18n.locales'))),
111
            ]);
112
    }
113
114
    /**
115
     * Get po result.
116
     *
117
     * @return array
118
     */
119
    public function getPoResult(): array
120
    {
121
        return $this->poResult;
122
    }
123
124
    /**
125
     * Get templatePaths.
126
     *
127
     * @return array
128
     */
129
    public function getTemplatePaths(): array
130
    {
131
        return $this->templatePaths;
132
    }
133
134
    /**
135
     * Get localePath
136
     *
137
     * @return string
138
     */
139
    public function getLocalePath(): string
140
    {
141
        return $this->localePath;
142
    }
143
144
    /**
145
     * Update gettext po files.
146
     *
147
     * @param \Cake\Console\Arguments $args The command arguments.
148
     * @param \Cake\Console\ConsoleIo $io The console io
149
     * @return null|void|int The exit code or null for success
150
     */
151
    public function execute(Arguments $args, ConsoleIo $io)
152
    {
153
        $resCmd = [];
154
        exec('which msgmerge 2>&1', $resCmd);
155
        if (empty($resCmd[0])) {
156
            $io->abort('ERROR: msgmerge not available. Please install gettext utilities.');
157
        }
158
159
        $io->out('Updating .pot and .po files...');
160
        $this->locales = array_filter(explode(',', $args->getOption('locales')));
0 ignored issues
show
Bug introduced by
It seems like $args->getOption('locales') can also be of type boolean and null; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

160
        $this->locales = array_filter(explode(',', /** @scrutinizer ignore-type */ $args->getOption('locales')));
Loading history...
161
        Paths::setup($this->templatePaths, $this->localePath, $this->defaultDomain, $args->getOptions());
162
        foreach ($this->templatePaths as $path) {
163
            $io->out(sprintf('Search in: %s', $path));
164
            File::parseDir($path, $this->defaultDomain, $this->poResult);
165
        }
166
167
        $io->out('Creating master .pot file');
168
        $result = Gettext::writeMasterPot($this->localePath, $this->poResult);
169
        foreach ($result['info'] as $info) {
170
            $io->out($info);
171
        }
172
        $hasChanges = Hash::get($result, 'updated') === true;
173
174
        $io->out('Extracting ttag translations from javascript files');
175
        $result = Ttag::extract($this->locales, $this->localePath, $args->getOption('plugin'));
0 ignored issues
show
Bug introduced by
It seems like $args->getOption('plugin') can also be of type boolean; however, parameter $plugin of BEdita\I18n\Filesystem\Ttag::extract() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

175
        $result = Ttag::extract($this->locales, $this->localePath, /** @scrutinizer ignore-type */ $args->getOption('plugin'));
Loading history...
176
        foreach ($result['info'] as $info) {
177
            $io->out($info);
178
        }
179
        $io->out(sprintf('Ttag extracted: %s', $result['extracted']));
180
181
        $io->hr();
182
        $io->out('Merging master .pot with current .po files');
183
        $io->hr();
184
185
        $io->out('Writing po files');
186
        $result = Gettext::writePoFiles($this->locales, $this->localePath, $this->poResult);
187
        foreach ($result['info'] as $info) {
188
            $io->out($info);
189
        }
190
191
        $io->out('Done');
192
193
        if ($args->getOption('ci') && $hasChanges) {
194
            return GettextCommand::CODE_CHANGES;
195
        }
196
197
        return GettextCommand::CODE_SUCCESS;
198
    }
199
}
200