• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

move-elevator / composer-translation-validator / 16402091592

20 Jul 2025 04:47PM UTC coverage: 96.554% (-0.009%) from 96.563%
16402091592

push

github

web-flow
Merge pull request #39 from move-elevator/file-headers

feat: add file headers to all PHP files for licensing and attribution

108 of 118 new or added lines in 32 files covered. (91.53%)

1737 of 1799 relevant lines covered (96.55%)

8.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.67
/src/Parser/XliffParser.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer plugin "composer-translation-validator".
7
 *
8
 * Copyright (C) 2025 Konrad Michalik <km@move-elevator.de>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace MoveElevator\ComposerTranslationValidator\Parser;
25

26
use InvalidArgumentException;
27
use SimpleXMLElement;
28

29
class XliffParser extends AbstractParser implements ParserInterface
30
{
31
    private readonly SimpleXMLElement|bool $xml;
32

33
    /**
34
     * @param string $filePath Path to the XLIFF file
35
     *
36
     * @throws InvalidArgumentException If file cannot be parsed as
37
     *                                  valid XML
38
     */
39
    public function __construct(protected string $filePath)
16✔
40
    {
41
        parent::__construct($filePath);
16✔
42

43
        $xmlContent = file_get_contents($filePath);
13✔
44
        if (false === $xmlContent) {
13✔
NEW
45
            throw new InvalidArgumentException("Failed to read file: {$filePath}");
×
46
        }
47

48
        libxml_use_internal_errors(true);
13✔
49
        $this->xml = simplexml_load_string($xmlContent);
13✔
50

51
        if (false === $this->xml) {
13✔
52
            throw new InvalidArgumentException("Failed to parse XML content from file: {$filePath}");
1✔
53
        }
54
        libxml_clear_errors();
12✔
55
    }
56

57
    /**
58
     * @return array<int, string>|null
59
     */
60
    public function extractKeys(): ?array
1✔
61
    {
62
        $keys = [];
1✔
63
        foreach ($this->xml->file->body->{'trans-unit'} as $unit) {
1✔
64
            $keys[] = (string) $unit['id'];
1✔
65
        }
66

67
        return $keys;
1✔
68
    }
69

70
    public function getContentByKey(string $key): ?string
5✔
71
    {
72
        $attribute = $this->hasTargetLanguage() ? 'target' : 'source';
5✔
73

74
        foreach ($this->xml->file->body->{'trans-unit'} as $unit) {
5✔
75
            if ((string) $unit['id'] === $key) {
5✔
76
                if ('' !== (string) $unit->{$attribute}) {
5✔
77
                    return (string) $unit->{$attribute};
2✔
78
                }
79

80
                if ('target' === $attribute && $this->hasTargetLanguage()) {
4✔
81
                    $fallbackContent = (string) $unit->source;
3✔
82
                    if ('' !== $fallbackContent) {
3✔
83
                        return $fallbackContent;
2✔
84
                    }
85
                }
86

87
                if ('source' === $attribute && !$this->hasTargetLanguage()) {
2✔
88
                    $fallbackContent = (string) $unit->target;
1✔
89
                    if ('' !== $fallbackContent) {
1✔
90
                        return $fallbackContent;
1✔
91
                    }
92
                }
93
            }
94
        }
95

96
        return null;
3✔
97
    }
98

99
    /**
100
     * @return array<int, string>
101
     */
102
    public static function getSupportedFileExtensions(): array
35✔
103
    {
104
        return ['xliff', 'xlf'];
35✔
105
    }
106

107
    public function getLanguage(): string
3✔
108
    {
109
        if (preg_match(
3✔
110
            '/^([a-z]{2})\./i',
3✔
111
            $this->getFileName(),
3✔
112
            $matches,
3✔
113
        )) {
3✔
114
            $language = $matches[1];
1✔
115
        } else {
116
            $language = (string) ($this->xml->file['source-language'] ?? '');
2✔
117
        }
118

119
        return $language;
3✔
120
    }
121

122
    private function hasTargetLanguage(): bool
5✔
123
    {
124
        return !empty((string) $this->xml->file['target-language']);
5✔
125
    }
126
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc