Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
52.94% covered (warning)
52.94%
18 / 34
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
LanguageFallbacks
52.94% covered (warning)
52.94%
18 / 34
66.67% covered (warning)
66.67%
2 / 3
14.67
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 loadFallbacks
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getFallbacks
50.00% covered (danger)
50.00%
16 / 32
0.00% covered (danger)
0.00%
0 / 1
10.50
1<?php
2/**
3 * @license GPL-2.0-or-later
4 * @file
5 */
6
7namespace Wikimedia\Leximorph\Provider;
8
9use Psr\Log\LoggerInterface;
10use Wikimedia\Leximorph\Util\JsonLoader;
11
12/**
13 * Provides functionality to retrieve fallback language codes for a given language.
14 *
15 * @since     1.45
16 * @author    Doğu Abaris (abaris@null.net)
17 */
18class LanguageFallbacks {
19
20    private const string FALLBACKS_PATH = __DIR__ . '/../data/language-fallback-mappings.json';
21
22    /**
23     * The fallback language codes for this instance's language.
24     *
25     * @var string[]|null
26     */
27    private ?array $fallbacks = null;
28
29    /**
30     * @since 1.45
31     */
32    public function __construct(
33        private readonly string $langCode,
34        private readonly LoggerInterface $logger,
35        private readonly JsonLoader $jsonLoader,
36    ) {
37    }
38
39    /**
40     * @since 1.45
41     * @return array<int|string, mixed> The entire fallback mapping.
42     */
43    private function loadFallbacks(): array {
44        return $this->jsonLoader->load( self::FALLBACKS_PATH, 'language fallback mappings' );
45    }
46
47    /**
48     * Returns fallback language codes for the instance's language code.
49     *
50     * @since 1.45
51     * @return string[] Fallback language codes.
52     */
53    public function getFallbacks(): array {
54        if ( $this->fallbacks === null ) {
55            $allFallbacks = $this->loadFallbacks();
56
57            $langNode = $allFallbacks[$this->langCode] ?? null;
58            $this->fallbacks = [];
59
60            if ( !is_array( $langNode ) ) {
61                $this->logger->warning(
62                    'Language fallback node missing or invalid.',
63                    [ 'langCode' => $this->langCode, 'type' => gettype( $langNode ) ]
64                );
65                return $this->fallbacks;
66            }
67
68            $fallbackValues = $langNode['values'] ?? null;
69
70            if ( !is_array( $fallbackValues ) ) {
71                $this->logger->warning(
72                    'Language fallback values missing or invalid.',
73                    [
74                        'langCode' => $this->langCode,
75                        'type' => gettype( $fallbackValues ),
76                    ]
77                );
78                return $this->fallbacks;
79            }
80
81            foreach ( $fallbackValues as $index => $value ) {
82                if ( is_string( $value ) ) {
83                    $this->fallbacks[] = $value;
84                } else {
85                    $this->logger->warning(
86                        'Invalid fallback value. Expected string, got {type}.',
87                        [
88                            'type' => gettype( $value ),
89                            'langCode' => $this->langCode,
90                            'index' => $index,
91                        ]
92                    );
93                }
94            }
95        }
96
97        return $this->fallbacks;
98    }
99}