Issues (2563)

app/Date/FrenchDate.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2025 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\Date;
21
22
use Fisharebest\ExtCalendar\FrenchCalendar;
23
use Fisharebest\Webtrees\I18N;
24
use Fisharebest\Webtrees\Services\RomanNumeralsService;
25
26
/**
27
 * Definitions for French Republican dates.
28
 */
29
class FrenchDate extends AbstractCalendarDate
30
{
31
    // GEDCOM calendar escape
32
    public const string ESCAPE = '@#DFRENCH R@';
0 ignored issues
show
A parse error occurred: Syntax error, unexpected T_STRING, expecting '=' on line 32 at column 24
Loading history...
33
34
    // Convert GEDCOM month names to month numbers
35
    protected const array MONTH_TO_NUMBER = [
36
        'VEND' => 1,
37
        'BRUM' => 2,
38
        'FRIM' => 3,
39
        'NIVO' => 4,
40
        'PLUV' => 5,
41
        'VENT' => 6,
42
        'GERM' => 7,
43
        'FLOR' => 8,
44
        'PRAI' => 9,
45
        'MESS' => 10,
46
        'THER' => 11,
47
        'FRUC' => 12,
48
        'COMP' => 13,
49
    ];
50
51
    protected const array NUMBER_TO_MONTH = [
52
        1 => 'VEND',
53
        2 => 'BRUM',
54
        3 => 'FRIM',
55
        4 => 'NIVO',
56
        5 => 'PLUV',
57
        6 => 'VENT',
58
        7 => 'GERM',
59
        8 => 'FLOR',
60
        9 => 'PRAI',
61
        10 => 'MESS',
62
        11 => 'THER',
63
        12 => 'FRUC',
64
        13 => 'COMP',
65
    ];
66
67
    private RomanNumeralsService $roman_numerals_service;
68
69
    /**
70
     * Create a date from either:
71
     * a Julian day number
72
     * day/month/year strings from a GEDCOM date
73
     * another CalendarDate object
74
     *
75
     * @param array<string>|int|AbstractCalendarDate $date
76
     */
77
    public function __construct($date)
78
    {
79
        $this->roman_numerals_service = new RomanNumeralsService();
80
        $this->calendar               = new FrenchCalendar();
81
82
        parent::__construct($date);
83
    }
84
85
    /**
86
     * Full month name in nominative case.
87
     *
88
     * @param int  $month
89
     * @param bool $leap_year Some calendars use leap months
90
     *
91
     * @return string
92
     */
93
    protected function monthNameNominativeCase(int $month, bool $leap_year): string
94
    {
95
        static $translated_month_names;
96
97
        if ($translated_month_names === null) {
98
            $translated_month_names = [
99
                0  => '',
100
                /* I18N: a month in the French republican calendar */
101
                1  => I18N::translateContext('NOMINATIVE', 'Vendemiaire'),
102
                /* I18N: a month in the French republican calendar */
103
                2  => I18N::translateContext('NOMINATIVE', 'Brumaire'),
104
                /* I18N: a month in the French republican calendar */
105
                3  => I18N::translateContext('NOMINATIVE', 'Frimaire'),
106
                /* I18N: a month in the French republican calendar */
107
                4  => I18N::translateContext('NOMINATIVE', 'Nivose'),
108
                /* I18N: a month in the French republican calendar */
109
                5  => I18N::translateContext('NOMINATIVE', 'Pluviose'),
110
                /* I18N: a month in the French republican calendar */
111
                6  => I18N::translateContext('NOMINATIVE', 'Ventose'),
112
                /* I18N: a month in the French republican calendar */
113
                /* I18N: a month in the French republican calendar */
114
                7  => I18N::translateContext('NOMINATIVE', 'Germinal'),
115
                /* I18N: a month in the French republican calendar */
116
                8  => I18N::translateContext('NOMINATIVE', 'Floreal'),
117
                /* I18N: a month in the French republican calendar */
118
                9  => I18N::translateContext('NOMINATIVE', 'Prairial'),
119
                /* I18N: a month in the French republican calendar */
120
                10 => I18N::translateContext('NOMINATIVE', 'Messidor'),
121
                /* I18N: a month in the French republican calendar */
122
                11 => I18N::translateContext('NOMINATIVE', 'Thermidor'),
123
                /* I18N: a month in the French republican calendar */
124
                12 => I18N::translateContext('NOMINATIVE', 'Fructidor'),
125
                /* I18N: a month in the French republican calendar */
126
                13 => I18N::translateContext('NOMINATIVE', 'jours complementaires'),
127
            ];
128
        }
129
130
        return $translated_month_names[$month];
131
    }
132
133
    /**
134
     * Full month name in genitive case.
135
     *
136
     * @param int  $month
137
     * @param bool $leap_year Some calendars use leap months
138
     *
139
     * @return string
140
     */
141
    protected function monthNameGenitiveCase(int $month, bool $leap_year): string
142
    {
143
        static $translated_month_names;
144
145
        if ($translated_month_names === null) {
146
            $translated_month_names = [
147
                0  => '',
148
                /* I18N: a month in the French republican calendar */
149
                1  => I18N::translateContext('GENITIVE', 'Vendemiaire'),
150
                /* I18N: a month in the French republican calendar */
151
                2  => I18N::translateContext('GENITIVE', 'Brumaire'),
152
                /* I18N: a month in the French republican calendar */
153
                3  => I18N::translateContext('GENITIVE', 'Frimaire'),
154
                /* I18N: a month in the French republican calendar */
155
                4  => I18N::translateContext('GENITIVE', 'Nivose'),
156
                /* I18N: a month in the French republican calendar */
157
                5  => I18N::translateContext('GENITIVE', 'Pluviose'),
158
                /* I18N: a month in the French republican calendar */
159
                6  => I18N::translateContext('GENITIVE', 'Ventose'),
160
                /* I18N: a month in the French republican calendar */
161
                7  => I18N::translateContext('GENITIVE', 'Germinal'),
162
                /* I18N: a month in the French republican calendar */
163
                8  => I18N::translateContext('GENITIVE', 'Floreal'),
164
                /* I18N: a month in the French republican calendar */
165
                9  => I18N::translateContext('GENITIVE', 'Prairial'),
166
                /* I18N: a month in the French republican calendar */
167
                10 => I18N::translateContext('GENITIVE', 'Messidor'),
168
                /* I18N: a month in the French republican calendar */
169
                11 => I18N::translateContext('GENITIVE', 'Thermidor'),
170
                /* I18N: a month in the French republican calendar */
171
                12 => I18N::translateContext('GENITIVE', 'Fructidor'),
172
                /* I18N: a month in the French republican calendar */
173
                13 => I18N::translateContext('GENITIVE', 'jours complementaires'),
174
            ];
175
        }
176
177
        return $translated_month_names[$month];
178
    }
179
180
    /**
181
     * Full month name in locative case.
182
     *
183
     * @param int  $month
184
     * @param bool $leap_year Some calendars use leap months
185
     *
186
     * @return string
187
     */
188
    protected function monthNameLocativeCase(int $month, bool $leap_year): string
189
    {
190
        static $translated_month_names;
191
192
        if ($translated_month_names === null) {
193
            $translated_month_names = [
194
                0  => '',
195
                /* I18N: a month in the French republican calendar */
196
                1  => I18N::translateContext('LOCATIVE', 'Vendemiaire'),
197
                /* I18N: a month in the French republican calendar */
198
                2  => I18N::translateContext('LOCATIVE', 'Brumaire'),
199
                /* I18N: a month in the French republican calendar */
200
                3  => I18N::translateContext('LOCATIVE', 'Frimaire'),
201
                /* I18N: a month in the French republican calendar */
202
                4  => I18N::translateContext('LOCATIVE', 'Nivose'),
203
                /* I18N: a month in the French republican calendar */
204
                5  => I18N::translateContext('LOCATIVE', 'Pluviose'),
205
                /* I18N: a month in the French republican calendar */
206
                6  => I18N::translateContext('LOCATIVE', 'Ventose'),
207
                /* I18N: a month in the French republican calendar */
208
                7  => I18N::translateContext('LOCATIVE', 'Germinal'),
209
                /* I18N: a month in the French republican calendar */
210
                8  => I18N::translateContext('LOCATIVE', 'Floreal'),
211
                /* I18N: a month in the French republican calendar */
212
                9  => I18N::translateContext('LOCATIVE', 'Prairial'),
213
                /* I18N: a month in the French republican calendar */
214
                10 => I18N::translateContext('LOCATIVE', 'Messidor'),
215
                /* I18N: a month in the French republican calendar */
216
                11 => I18N::translateContext('LOCATIVE', 'Thermidor'),
217
                /* I18N: a month in the French republican calendar */
218
                12 => I18N::translateContext('LOCATIVE', 'Fructidor'),
219
                /* I18N: a month in the French republican calendar */
220
                13 => I18N::translateContext('LOCATIVE', 'jours complementaires'),
221
            ];
222
        }
223
224
        return $translated_month_names[$month];
225
    }
226
227
    /**
228
     * Full month name in instrumental case.
229
     *
230
     * @param int  $month
231
     * @param bool $leap_year Some calendars use leap months
232
     *
233
     * @return string
234
     */
235
    protected function monthNameInstrumentalCase(int $month, bool $leap_year): string
236
    {
237
        static $translated_month_names;
238
239
        if ($translated_month_names === null) {
240
            $translated_month_names = [
241
                0  => '',
242
                /* I18N: a month in the French republican calendar */
243
                1  => I18N::translateContext('INSTRUMENTAL', 'Vendemiaire'),
244
                /* I18N: a month in the French republican calendar */
245
                2  => I18N::translateContext('INSTRUMENTAL', 'Brumaire'),
246
                /* I18N: a month in the French republican calendar */
247
                3  => I18N::translateContext('INSTRUMENTAL', 'Frimaire'),
248
                /* I18N: a month in the French republican calendar */
249
                4  => I18N::translateContext('INSTRUMENTAL', 'Nivose'),
250
                /* I18N: a month in the French republican calendar */
251
                5  => I18N::translateContext('INSTRUMENTAL', 'Pluviose'),
252
                /* I18N: a month in the French republican calendar */
253
                6  => I18N::translateContext('INSTRUMENTAL', 'Ventose'),
254
                /* I18N: a month in the French republican calendar */
255
                7  => I18N::translateContext('INSTRUMENTAL', 'Germinal'),
256
                /* I18N: a month in the French republican calendar */
257
                8  => I18N::translateContext('INSTRUMENTAL', 'Floreal'),
258
                /* I18N: a month in the French republican calendar */
259
                9  => I18N::translateContext('INSTRUMENTAL', 'Prairial'),
260
                /* I18N: a month in the French republican calendar */
261
                10 => I18N::translateContext('INSTRUMENTAL', 'Messidor'),
262
                /* I18N: a month in the French republican calendar */
263
                11 => I18N::translateContext('INSTRUMENTAL', 'Thermidor'),
264
                /* I18N: a month in the French republican calendar */
265
                12 => I18N::translateContext('INSTRUMENTAL', 'Fructidor'),
266
                /* I18N: a month in the French republican calendar */
267
                13 => I18N::translateContext('INSTRUMENTAL', 'jours complementaires'),
268
            ];
269
        }
270
271
        return $translated_month_names[$month];
272
    }
273
274
    /**
275
     * Abbreviated month name
276
     *
277
     * @param int  $month
278
     * @param bool $leap_year Some calendars use leap months
279
     *
280
     * @return string
281
     */
282
    protected function monthNameAbbreviated(int $month, bool $leap_year): string
283
    {
284
        return $this->monthNameNominativeCase($month, $leap_year);
285
    }
286
287
    /**
288
     * Full day of the week
289
     *
290
     * @param int $day_number
291
     *
292
     * @return string
293
     */
294
    public function dayNames(int $day_number): string
295
    {
296
        static $translated_day_names;
297
298
        if ($translated_day_names === null) {
299
            $translated_day_names = [
300
                /* I18N: The first day in the French republican calendar */
301
                0 => I18N::translate('Primidi'),
302
                /* I18N: The second day in the French republican calendar */
303
                1 => I18N::translate('Duodi'),
304
                /* I18N: The third day in the French republican calendar */
305
                2 => I18N::translate('Tridi'),
306
                /* I18N: The fourth day in the French republican calendar */
307
                3 => I18N::translate('Quartidi'),
308
                /* I18N: The fifth day in the French republican calendar */
309
                4 => I18N::translate('Quintidi'),
310
                /* I18N: The sixth day in the French republican calendar */
311
                5 => I18N::translate('Sextidi'),
312
                /* I18N: The seventh day in the French republican calendar */
313
                6 => I18N::translate('Septidi'),
314
                /* I18N: The eighth day in the French republican calendar */
315
                7 => I18N::translate('Octidi'),
316
                /* I18N: The ninth day in the French republican calendar */
317
                8 => I18N::translate('Nonidi'),
318
                /* I18N: The tenth day in the French republican calendar */
319
                9 => I18N::translate('Decidi'),
320
            ];
321
        }
322
323
        return $translated_day_names[$day_number];
324
    }
325
326
    /**
327
     * Abbreviated day of the week
328
     *
329
     * @param int $day_number
330
     *
331
     * @return string
332
     */
333
    protected function dayNamesAbbreviated(int $day_number): string
334
    {
335
        return $this->dayNames($day_number);
336
    }
337
338
    /**
339
     * Generate the %Y format for a date.
340
     *
341
     * @return string
342
     */
343
    protected function formatLongYear(): string
344
    {
345
        return 'An ' . $this->roman_numerals_service->numberToRomanNumerals($this->year);
346
    }
347
}
348