Passed
Push — master ( 0e0687...5606fe )
by Dante
01:10
created

GettextCommand   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 135
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 66
c 3
b 1
f 0
dl 0
loc 135
rs 10
wmc 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
C execute() 0 45 9
A buildOptionParser() 0 35 1
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
    private $poResult = [];
45
46
    /**
47
     * The template paths
48
     *
49
     * @var array
50
     */
51
    private $templatePaths = [];
52
53
    /**
54
     * The locale path
55
     *
56
     * @var string
57
     */
58
    private $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
    private $defaultDomain = 'default';
66
67
    /**
68
     * The locales to generate.
69
     *
70
     * @var array
71
     */
72
    private $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
                '`bin/cake gettext --plugins`: update files for all the plugins',
87
            ])
88
            ->addOption('app', [
89
                'help' => 'The app path, for i18n update.',
90
                'short' => 'a',
91
                'required' => false,
92
            ])
93
            ->addOption('plugin', [
94
                'help' => 'The plugin name, for i18n update.',
95
                'short' => 'p',
96
                'required' => false,
97
            ])
98
            ->addOption('plugins', [
99
                'help' => 'All plugins',
100
                'required' => false,
101
                'boolean' => true,
102
            ])
103
            ->addOption('ci', [
104
                'help' => 'Run in CI mode. Exit with error if PO files are changed.',
105
                'required' => false,
106
                'boolean' => true,
107
            ])
108
            ->addOption('locales', [
109
                'help' => 'Comma separated list of locales to generate. Leave empty to use configuration `I18n.locales`',
110
                'short' => 'l',
111
                'default' => implode(',', array_keys((array)Configure::read('I18n.locales'))),
112
            ]);
113
    }
114
115
    /**
116
     * Update gettext po files.
117
     *
118
     * @param \Cake\Console\Arguments $args The command arguments.
119
     * @param \Cake\Console\ConsoleIo $io The console io
120
     * @return null|void|int The exit code or null for success
121
     */
122
    public function execute(Arguments $args, ConsoleIo $io)
123
    {
124
        $io->out('Start');
125
126
        $resCmd = [];
127
        exec('which msgmerge 2>&1', $resCmd);
128
        $msg = empty($resCmd[0]) ? 'ERROR: msgmerge not available. Please install gettext utilities.' : 'OK: msgmerge found';
129
        $method = empty($resCmd[0]) ? 'abort' : 'out';
130
        $io->{$method}($msg);
131
132
        $io->out('Updating .pot and .po files...');
133
        $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

133
        $this->locales = array_filter(explode(',', /** @scrutinizer ignore-type */ $args->getOption('locales')));
Loading history...
134
        Paths::setup($this->templatePaths, $this->localePath, $this->defaultDomain, $args->getOptions());
135
        foreach ($this->templatePaths as $path) {
136
            $io->out(sprintf('Search in: %s', $path));
137
            File::parseDir($path, $this->defaultDomain, $this->poResult);
138
        }
139
140
        $io->out('Creating master .pot file');
141
        $result = Gettext::writeMasterPot($this->localePath, $this->poResult);
142
        foreach ($result['info'] as $info) {
143
            $io->out($info);
144
        }
145
        $hasChanges = Hash::get($result, 'updated') === true;
146
147
        $io->out('Extracting ttag translations from javascript files');
148
        $result = Ttag::extract($this->locales, $this->localePath, (string)$args->getOption('plugin'));
149
        foreach ($result['info'] as $info) {
150
            $io->out($info);
151
        }
152
        $io->out(sprintf('Ttag extracted: %s', $result['extracted']));
153
154
        $io->hr();
155
        $io->out('Merging master .pot with current .po files');
156
        $io->hr();
157
158
        $io->out('Writing po files');
159
        $result = Gettext::writePoFiles($this->locales, $this->localePath, $this->poResult);
160
        foreach ($result['info'] as $info) {
161
            $io->out($info);
162
        }
163
164
        $io->out('Done');
165
166
        return $args->getOption('ci') && $hasChanges ? GettextCommand::CODE_CHANGES : GettextCommand::CODE_SUCCESS;
167
    }
168
}
169