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

Ttag::extract()   A

Complexity

Conditions 6
Paths 32

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 13
c 1
b 0
f 0
nc 32
nop 3
dl 0
loc 24
rs 9.2222
1
<?php
2
declare(strict_types=1);
3
4
/**
5
 * BEdita, API-first content management framework
6
 * Copyright 2023 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\Filesystem;
17
18
use Cake\Core\App;
19
use Cake\Core\Plugin;
20
use Cake\Utility\Hash;
21
use Cake\View\View;
22
23
/**
24
 * Ttag utility class.
25
 *
26
 * Extract ttag strings from javascript files.
27
 * Requires ttag-cli to be installed.
28
 */
29
class Ttag
30
{
31
    /**
32
     * Extract ttag strings from javascript files.
33
     * Returns an array with two keys:
34
     *
35
     * - extracted: true if extraction was successful, false otherwise
36
     * - info: an array of strings with info messages
37
     *
38
     * @param array $locales The locales
39
     * @param string $localePath The locale path
40
     * @param string|null $plugin The plugin name, if any
41
     * @return array
42
     */
43
    public static function extract(array $locales, string $localePath, ?string $plugin = null): array
44
    {
45
        $skip = false;
46
        $info = [];
47
48
        // check ttag command exists
49
        $ttag = 'node_modules/ttag-cli/bin/ttag';
50
        if (!file_exists($ttag)) {
51
            $info[] = sprintf('Skip javascript parsing - %s command not found', $ttag);
52
            $skip = true;
53
        }
54
55
        // check template folder exists
56
        $appDir = !empty($plugin) ? Plugin::templatePath($plugin) : Hash::get(App::path(View::NAME_TEMPLATE), 0);
57
        if (!file_exists($appDir)) {
0 ignored issues
show
Bug introduced by
It seems like $appDir can also be of type null; however, parameter $filename of file_exists() 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

57
        if (!file_exists(/** @scrutinizer ignore-type */ $appDir)) {
Loading history...
58
            $info[] = sprintf('Skip javascript parsing - %s folder not found', $appDir);
59
            $skip = true;
60
        }
61
62
        // do extract translation strings from js files using ttag
63
        $info[] = 'Extracting translation string from javascript files using ttag' . ($skip ? ' (skipped)' : '');
64
        $extracted = $skip ? false : self::doExtract($ttag, (string)$appDir, $localePath, $locales);
65
66
        return compact('extracted', 'info');
67
    }
68
69
    /**
70
     * Perform ttag extract.
71
     * Returns true if extraction was successful, false otherwise.
72
     *
73
     * @param string $ttag Ttag command
74
     * @param string $appDir Path to the app directory
75
     * @param string $localePath Path to the locale directory
76
     * @param array $locales The locales
77
     * @param string|null $plugin The plugin name, if any
78
     * @return bool
79
     */
80
    public static function doExtract(
81
        string $ttag,
82
        string $appDir,
83
        string $localePath,
84
        array $locales,
85
        ?string $plugin = null
86
    ): bool {
87
        $result = true;
88
        try {
89
            // Path to the resources directory defined in cakephp app config/paths.php
90
            // Do not add RESOURCES path when it's a plugin
91
            $useResources = empty($plugin) && defined('RESOURCES') && file_exists(RESOURCES);
92
            $appDir = $useResources ? sprintf('%s %s', $appDir, RESOURCES) : $appDir;// @phpstan-ignore-line
93
94
            $defaultJs = sprintf('%s/default-js.pot', $localePath);
95
            foreach ($locales as $locale) {
96
                $lang = substr($locale, 0, 2);
97
                exec(sprintf('%s extract --extractLocation never --o %s --l %s %s', $ttag, $defaultJs, $lang, $appDir));
98
            }
99
100
            // merge default-js.pot and <plugin>.pot|default.pot
101
            $potFile = !empty($plugin) && is_string($plugin) ? sprintf('%s.pot', $plugin) : 'default.pot';
102
            $default = sprintf('%s/%s', $localePath, $potFile);
103
            exec(sprintf('msgcat --use-first %s %s -o %s', $default, $defaultJs, $default));
104
105
            // remove default-js.pot
106
            unlink($defaultJs);
107
        } catch (\Throwable $e) {
108
            $result = false;
109
        }
110
111
        return $result;
112
    }
113
}
114