Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
GeneratePoFilesCommand
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 2
42
0.00% covered (danger)
0.00%
0 / 1
 execute
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 generatePoContent
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2declare(strict_types=1);
3
4namespace App\Command;
5
6use App\Utility\I18nManager;
7use Cake\Command\Command;
8use Cake\Console\Arguments;
9use Cake\Console\ConsoleIo;
10use Cake\Datasource\ResultSetInterface;
11use Cake\ORM\TableRegistry;
12use Cake\Utility\Filesystem;
13
14/**
15 * Class GeneratePoFilesCommand
16 *
17 * This command generates default.po files for each locale based on the translations in the database.
18 */
19class GeneratePoFilesCommand extends Command
20{
21    /**
22     * Executes the command to generate default.po files.
23     *
24     * @param \Cake\Console\Arguments $args The command line arguments.
25     * @param \Cake\Console\ConsoleIo $io The console input/output.
26     * @return int The exit code.
27     */
28    public function execute(Arguments $args, ConsoleIo $io): int
29    {
30        $locales = I18nManager::$locales;
31
32        // Fetch the I18n table
33        $i18nTable = TableRegistry::getTableLocator()->get('internationalisations');
34
35        $filesystem = new Filesystem();
36
37        foreach ($locales as $locale) {
38            $translations = $i18nTable->find()
39                ->where(['locale' => $locale, 'message_str !=' => ''])
40                ->all();
41
42            // Check if there are any translations for the locale
43            if ($translations->isEmpty()) {
44                $io->out(sprintf('No translations found for locale: %s. Skipping...', $locale));
45                continue;
46            }
47
48            $poContent = $this->generatePoContent($locale, $translations);
49
50            $filePath = ROOT . DS . 'resources' . DS . 'locales' . DS . $locale . DS . 'default.po';
51            $dirPath = dirname($filePath);
52
53            if (!is_dir($dirPath)) {
54                mkdir($dirPath, 0755, true);
55            }
56
57            $filesystem->dumpFile($filePath, $poContent);
58            $io->out(sprintf('Generated default.po for locale: %s', $locale));
59        }
60
61        return Command::CODE_SUCCESS;
62    }
63
64    /**
65     * Generates the content for a .po file.
66     *
67     * @param string $locale The locale for which the .po file is generated.
68     * @param \Cake\Datasource\ResultSetInterface $translations The translations to include in the .po file.
69     * @return string The content of the .po file.
70     */
71    protected function generatePoContent(string $locale, ResultSetInterface $translations): string
72    {
73        $header = <<<EOT
74# LANGUAGE translation of CakePHP Application
75# Copyright YEAR NAME <EMAIL@ADDRESS>
76#
77#, fuzzy
78msgid ""
79msgstr ""
80"Project-Id-Version: PROJECT VERSION"
81"POT-Creation-Date: 2024-10-23 23:47+0100"
82"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ"
83"Last-Translator: NAME <EMAIL@ADDRESS>"
84"Language-Team: LANGUAGE <EMAIL@ADDRESS>"
85"MIME-Version: 1.0"
86"Content-Type: text/plain; charset=utf-8"
87"Content-Transfer-Encoding: 8bit"
88"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;"
89
90EOT;
91
92        $body = '';
93        foreach ($translations as $translation) {
94            $body .= "#: {$translation->context}\n";
95            $body .= "msgid \"{$translation->message_id}\"\n";
96            $body .= "msgstr \"{$translation->message_str}\"\n\n";
97        }
98
99        return $header . $body;
100    }
101}