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