Passed
Push — dbal ( 396fa2...d36e46 )
by Greg
11:43
created

LocalizationService   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 163
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 12
eloc 80
c 2
b 0
f 0
dl 0
loc 163
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A alphabet() 0 6 1
A initialLetter() 0 14 3
A dateFormatToOrder() 0 11 3
A calendar() 0 10 1
A collation() 0 12 4
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2022 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees\Services;
21
22
use Fisharebest\ExtCalendar\ArabicCalendar;
23
use Fisharebest\ExtCalendar\CalendarInterface;
24
use Fisharebest\ExtCalendar\GregorianCalendar;
25
use Fisharebest\ExtCalendar\JewishCalendar;
26
use Fisharebest\ExtCalendar\PersianCalendar;
27
use Fisharebest\Localization\Locale\LocaleInterface;
28
use Fisharebest\Webtrees\I18N;
29
30
use function strlen;
31
use function substr_compare;
32
33
/**
34
 * Utilities to support localization.
35
 *
36
 * @deprecated - Will be removed in webtrees 2.2 - Use I18N::language() instead
37
 */
38
class LocalizationService
39
{
40
    // Alphabets used by various scripts and locales.
41
    private const ARABIC_ALPHABET     = ['ا', 'ب', 'ت', 'ث', 'ج', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز', 'س', 'ش', 'ص', 'ض', 'ط', 'ظ', 'ع', 'غ', 'ف', 'ق', 'ك', 'ل', 'م', 'ن', 'ه', 'و', 'ي', 'آ', 'ة', 'ى', 'ی'];
42
    private const CZECH_ALPHABET      = ['A', 'Á', 'B', 'C', 'Č', 'D', 'Ď', 'E', 'É', 'Ě', 'F', 'G', 'H', 'CH', 'I', ' 	Í', 'J', 'K', 'L', 'M', 'N', 'Ň', 'O', 'Ó', 'P', 'Q', 'R', 'Ř', 'S', 'Š', 'T', 'Ť', 'U', 'Ú', 'Ů', 'V', 'W', 'X', 'Y', 'Ý', 'Z', 'Ž'];
43
    private const CYRILLIC_ALPHABET   = ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я'];
44
    private const DUTCH_ALPHABET      = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'IJ'];
45
    private const ESTONIAN_ALPHABET   = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'Z', 'Ž', 'T', 'U', 'V', 'W', 'Õ', 'Ä', 'Ö', 'Ü', 'X', 'Y'];
46
    private const GREEK_ALPHABET      = ['Α', 'Β', 'Γ', 'Δ', 'Ε', 'Ζ', 'Η', 'Θ', 'Ι', 'Κ', 'Λ', 'Μ', 'Ν', 'Ξ', 'Ο', 'Π', 'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω'];
47
    private const HEBREW_ALPHABET     = ['א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ', 'ק', 'ר', 'ש', 'ת'];
48
    private const LATIN_ALPHABET      = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
49
    private const LITHUANIAN_ALPHABET = ['A', 'Ą', 'B', 'C', 'Č', 'D', 'E', 'Ę', 'Ė', 'F', 'G', 'H', 'I', 'Y', 'Į', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'Š', 'T', 'U', 'Ų', 'Ū', 'V', 'Z', 'Ž'];
50
    private const HUNGARIAN_ALPHABET  = ['A', 'Á', 'B', 'C', 'CS', 'D', 'DZ', 'DZS', 'E', 'É', 'F', 'G', 'GY', 'H', 'I', 'Í', 'J', 'K', 'L', 'LY', 'M', 'N', 'NY', 'O', 'Ó', 'Ö', 'Ő', 'P', 'Q', 'R', 'S', 'SZ', 'T', 'TY', 'U', 'Ú', 'Ü', 'Ű', 'V', 'W', 'X', 'Y', 'Z', 'ZS'];
51
    private const NORWEGIAN_ALPHABET  = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Æ', 'Ø', 'Å'];
52
    private const POLISH_ALPHABET     = ['A', 'B', 'C', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'Ł', 'M', 'N', 'O', 'Ó', 'P', 'Q', 'R', 'S', 'Ś', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ź', 'Ż'];
53
    private const ROMANIAN_ALPHABET   = ['A', 'Ă', 'Â', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'Î', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Ş', 'T', 'Ţ', 'U', 'V', 'W', 'X', 'Y', 'Z'];
54
    private const SERBIAN_ALPHABET    = ['A', 'B', 'C', 'Č', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ž'];
55
    private const SLOVAKIAN_ALPHABET  = ['A', 'Á', 'Ä', 'B', 'C', 'Č', 'D', 'Ď', 'DZ', 'DŽ', 'E', 'É', 'F', 'G', 'H', 'CH', 'I', 'Í', 'J', 'K', 'L', 'Ľ', 'Ĺ', 'M', 'N', 'Ň', 'O', 'Ó', 'Ô', 'P', 'Q', 'R', 'Ŕ', 'S', 'Š', 'T', 'Ť', 'U', 'Ú', 'V', 'W', 'X', 'Y', 'Ý', 'Z', 'Ž'];
56
    private const SLOVENIAN_ALPHABET  = ['A', 'B', 'C', 'Č', 'Ć', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Ž'];
57
    private const SPANISH_ALPHABET    = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'Ñ', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
58
    private const SWEDISH_ALPHABET    = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'Å', 'Ä', 'Ö'];
59
    private const TURKISH_ALPHABET    = ['A', 'B', 'C', 'Ç', 'D', 'E', 'F', 'G', 'Ğ', 'H', 'I', 'İ', 'J', 'K', 'L', 'M', 'N', 'O', 'Ö', 'P', 'R', 'S', 'Ş', 'T', 'U', 'Ü', 'V', 'Y', 'Z'];
60
61
    // Scripts with a default alphabet.
62
    private const ALPHABETS_FOR_SCRIPT = [
63
        'Latn' => self::LATIN_ALPHABET,
64
        'Cyrl' => self::CYRILLIC_ALPHABET,
65
        'Grek' => self::GREEK_ALPHABET,
66
        'Hebr' => self::HEBREW_ALPHABET,
67
    ];
68
69
    // Locales that use a non-default alphabet.
70
    private const ALPHABETS = [
71
        'ar'      => self::ARABIC_ALPHABET,
72
        'cs'      => self::CZECH_ALPHABET,
73
        'da'      => self::NORWEGIAN_ALPHABET,
74
        'es'      => self::SPANISH_ALPHABET,
75
        'et'      => self::ESTONIAN_ALPHABET,
76
        'fa'      => self::ARABIC_ALPHABET,
77
        'fi'      => self::SWEDISH_ALPHABET,
78
        'hu'      => self::HUNGARIAN_ALPHABET,
79
        'lt'      => self::LITHUANIAN_ALPHABET,
80
        'nb'      => self::NORWEGIAN_ALPHABET,
81
        'nl'      => self::DUTCH_ALPHABET,
82
        'nn'      => self::NORWEGIAN_ALPHABET,
83
        'pl'      => self::POLISH_ALPHABET,
84
        'ro'      => self::ROMANIAN_ALPHABET,
85
        'sk'      => self::SLOVAKIAN_ALPHABET,
86
        'sl'      => self::SLOVENIAN_ALPHABET,
87
        'sr-Latn' => self::SERBIAN_ALPHABET,
88
        'tr'      => self::TURKISH_ALPHABET,
89
        'sv'      => self::SWEDISH_ALPHABET,
90
    ];
91
92
    // Some languages collate names using digraphs (or trigraphs).
93
    private const DIGRAPHS = [
94
        'cs' => ['CH' => 'CH'],
95
        'da' => ['AA' => 'Å'],
96
        'nb' => ['AA' => 'Å'],
97
        'hu' => ['CS' => 'CS', 'DZS' => 'DZS', 'DZ' => 'DZ', 'GY' => 'GY', 'LY' => 'LY', 'NY' => 'NY', 'SZ' => 'SZ', 'TY' => 'TY', 'ZS' => 'ZS'],
98
        'nl' => ['IJ' => 'IJ'],
99
        'nn' => ['AA' => 'Å'],
100
        'sk' => ['DZ' => 'DZ', 'DŽ' => 'DŽ','CH' => 'CH'],
101
    ];
102
103
    /**
104
     * Which alphabet is used in a locale?
105
     *
106
     * @param LocaleInterface $locale
107
     *
108
     * @return array<string>
109
     */
110
    public function alphabet(LocaleInterface $locale): array
111
    {
112
        $language = $locale->languageTag();
113
        $script   = $locale->script()->code();
114
115
        return self::ALPHABETS[$language] ?? self::ALPHABETS_FOR_SCRIPT[$script] ?? self::LATIN_ALPHABET;
116
    }
117
118
    /**
119
     * Which calendar is used in a locale?
120
     *
121
     * @param LocaleInterface $locale
122
     *
123
     * @return CalendarInterface
124
     */
125
    public function calendar(LocaleInterface $locale): CalendarInterface
126
    {
127
        $non_gregorian_calendars = [
128
            'ar' => new ArabicCalendar(),
129
            'fa' => new PersianCalendar(),
130
            'he' => new JewishCalendar(),
131
            'yi' => new JewishCalendar(),
132
        ];
133
134
        return $non_gregorian_calendars[$locale->languageTag()] ?? new GregorianCalendar();
135
    }
136
137
    /**
138
     * Which MySQL collation should be used for this locale?
139
     *
140
     * @param LocaleInterface $locale
141
     *
142
     * @return string
143
     */
144
    public function collation(LocaleInterface $locale): string
145
    {
146
        $collation = $locale->collation();
147
148
        switch ($collation) {
149
            case 'croatian_ci':
150
            case 'german2_ci':
151
            case 'vietnamese_ci':
152
                // Only available in MySQL 5.6
153
                return 'utf8_unicode_ci';
154
            default:
155
                return 'utf8_' . $collation;
156
        }
157
    }
158
159
    /**
160
     * Extract the initial letter (or digraph or trigraph) from a name.
161
     *
162
     * @param string          $text
163
     * @param LocaleInterface $locale
164
     *
165
     * @return string
166
     */
167
    public function initialLetter(string $text, LocaleInterface $locale): string
168
    {
169
        $text = I18N::strtoupper($text);
170
171
        $digraphs = self::DIGRAPHS[$locale->languageTag()] ?? [];
172
173
        foreach ($digraphs as $key => $value) {
174
            if (substr_compare($text, $key, 0, strlen($key)) === 0) {
175
                return $value;
176
            }
177
        }
178
179
        // No special rules - just take the first character
180
        return mb_substr($text, 0, 1);
181
    }
182
183
    /**
184
     * Convert a PHP date format string into DMY, MDY or YMD
185
     *
186
     * @param string $format
187
     *
188
     * @return string
189
     */
190
    public function dateFormatToOrder(string $format): string
191
    {
192
        if (preg_match('/[yY].*[mnFM].*[dj]/', $format)) {
193
            return 'YMD';
194
        }
195
196
        if (preg_match('/[mnFM].*[dj].*[yY]/', $format)) {
197
            return 'MDY';
198
        }
199
200
        return 'DMY';
201
    }
202
}
203