Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
Status
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
3 / 3
9
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 run
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 inspect
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2
3declare(strict_types=1);
4
5namespace Celemas\Verba\Tool;
6
7/**
8 * Reports translation gaps for a domain without touching any files: per locale,
9 * how many source messages are missing from the catalog, present but
10 * untranslated, translated, and how many catalog entries are now obsolete.
11 *
12 * @api
13 */
14final class Status
15{
16    public function __construct(
17        private readonly Domain $domain,
18    ) {}
19
20    public function run(): StatusReport
21    {
22        $extraction = new Extractor($this->domain)->extract();
23        $fresh = $extraction['messages'];
24
25        $locales = [];
26
27        foreach ($this->domain->locales as $locale) {
28            $locales[$locale] = $this->inspect($locale, $fresh);
29        }
30
31        return new StatusReport($this->domain->name, $locales, $extraction['warnings']);
32    }
33
34    /**
35     * @param array<string, Message> $fresh
36     * @return array{
37     *     missing: int,
38     *     untranslated: int,
39     *     translated: int,
40     *     obsolete: int,
41     *     total: int,
42     *     locations: list<string>,
43     * }
44     */
45    private function inspect(string $locale, array $fresh): array
46    {
47        $catalog = CatalogFile::load($this->domain->file($locale));
48
49        $missing = 0;
50        $untranslated = 0;
51        $translated = 0;
52        $locations = [];
53
54        foreach ($fresh as $id => $message) {
55            if (!array_key_exists($id, $catalog->messages)) {
56                $missing++;
57                $locations = [...$locations, ...$message->locations];
58            } elseif ($catalog->messages[$id] === null) {
59                $untranslated++;
60                $locations = [...$locations, ...$message->locations];
61            } else {
62                $translated++;
63            }
64        }
65
66        $obsolete = 0;
67
68        foreach (array_keys($catalog->messages) as $id) {
69            if (array_key_exists($id, $fresh)) {
70                continue;
71            }
72
73            $obsolete++;
74        }
75
76        return [
77            'missing' => $missing,
78            'untranslated' => $untranslated,
79            'translated' => $translated,
80            'obsolete' => $obsolete,
81            'total' => count($fresh),
82            'locations' => $locations,
83        ];
84    }
85}