xref: /webtrees/app/Date/FrenchDate.php (revision d11be7027e34e3121be11cc025421873364403f9)
1a25f0a04SGreg Roach<?php
23976b470SGreg Roach
3a25f0a04SGreg Roach/**
4a25f0a04SGreg Roach * webtrees: online genealogy
5*d11be702SGreg Roach * Copyright (C) 2023 webtrees development team
6a25f0a04SGreg Roach * This program is free software: you can redistribute it and/or modify
7a25f0a04SGreg Roach * it under the terms of the GNU General Public License as published by
8a25f0a04SGreg Roach * the Free Software Foundation, either version 3 of the License, or
9a25f0a04SGreg Roach * (at your option) any later version.
10a25f0a04SGreg Roach * This program is distributed in the hope that it will be useful,
11a25f0a04SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
12a25f0a04SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13a25f0a04SGreg Roach * GNU General Public License for more details.
14a25f0a04SGreg Roach * You should have received a copy of the GNU General Public License
1589f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>.
16a25f0a04SGreg Roach */
17fcfa147eSGreg Roach
18e7f56f2aSGreg Roachdeclare(strict_types=1);
19e7f56f2aSGreg Roach
2076692c8bSGreg Roachnamespace Fisharebest\Webtrees\Date;
21a25f0a04SGreg Roach
22a25f0a04SGreg Roachuse Fisharebest\ExtCalendar\FrenchCalendar;
230e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
244ba350e3SGreg Roachuse Fisharebest\Webtrees\Services\RomanNumeralsService;
25a25f0a04SGreg Roach
26a25f0a04SGreg Roach/**
274a83f5d7SGreg Roach * Definitions for French Republican dates.
28a25f0a04SGreg Roach */
294a83f5d7SGreg Roachclass FrenchDate extends AbstractCalendarDate
30c1010edaSGreg Roach{
314a83f5d7SGreg Roach    // GEDCOM calendar escape
3216d6367aSGreg Roach    public const ESCAPE = '@#DFRENCH R@';
334a83f5d7SGreg Roach
3452348eb8SGreg Roach    // Convert GEDCOM month names to month numbers
35d8809d62SGreg Roach    protected const MONTH_TO_NUMBER = [
36c1010edaSGreg Roach        'VEND' => 1,
37c1010edaSGreg Roach        'BRUM' => 2,
38c1010edaSGreg Roach        'FRIM' => 3,
39c1010edaSGreg Roach        'NIVO' => 4,
40c1010edaSGreg Roach        'PLUV' => 5,
41c1010edaSGreg Roach        'VENT' => 6,
42c1010edaSGreg Roach        'GERM' => 7,
43c1010edaSGreg Roach        'FLOR' => 8,
44c1010edaSGreg Roach        'PRAI' => 9,
45c1010edaSGreg Roach        'MESS' => 10,
46c1010edaSGreg Roach        'THER' => 11,
47c1010edaSGreg Roach        'FRUC' => 12,
48c1010edaSGreg Roach        'COMP' => 13,
49c1010edaSGreg Roach    ];
50a25f0a04SGreg Roach
51d8809d62SGreg Roach    protected const NUMBER_TO_MONTH = [
52d8809d62SGreg Roach        1 => 'VEND',
53d8809d62SGreg Roach        2 => 'BRUM',
54d8809d62SGreg Roach        3 => 'FRIM',
55d8809d62SGreg Roach        4 => 'NIVO',
56d8809d62SGreg Roach        5 => 'PLUV',
57d8809d62SGreg Roach        6 => 'VENT',
58d8809d62SGreg Roach        7 => 'GERM',
59d8809d62SGreg Roach        8 => 'FLOR',
60d8809d62SGreg Roach        9 => 'PRAI',
61d8809d62SGreg Roach        10 => 'MESS',
62d8809d62SGreg Roach        11 => 'THER',
63d8809d62SGreg Roach        12 => 'FRUC',
64d8809d62SGreg Roach        13 => 'COMP',
65d8809d62SGreg Roach    ];
66d8809d62SGreg Roach
6743f2f523SGreg Roach    private RomanNumeralsService $roman_numerals_service;
684ba350e3SGreg Roach
6976692c8bSGreg Roach    /**
7076692c8bSGreg Roach     * Create a date from either:
7176692c8bSGreg Roach     * a Julian day number
7276692c8bSGreg Roach     * day/month/year strings from a GEDCOM date
7376692c8bSGreg Roach     * another CalendarDate object
7476692c8bSGreg Roach     *
75f4c767fdSGreg Roach     * @param array<string>|int|AbstractCalendarDate $date
7676692c8bSGreg Roach     */
77c1010edaSGreg Roach    public function __construct($date)
78c1010edaSGreg Roach    {
794ba350e3SGreg Roach        $this->roman_numerals_service = new RomanNumeralsService();
8059f2f229SGreg Roach        $this->calendar               = new FrenchCalendar();
814ba350e3SGreg Roach
82a25f0a04SGreg Roach        parent::__construct($date);
83a25f0a04SGreg Roach    }
84a25f0a04SGreg Roach
8576692c8bSGreg Roach    /**
8676692c8bSGreg Roach     * Full month name in nominative case.
8776692c8bSGreg Roach     *
887bb2eb25SGreg Roach     * @param int  $month
8976692c8bSGreg Roach     * @param bool $leap_year Some calendars use leap months
9076692c8bSGreg Roach     *
9176692c8bSGreg Roach     * @return string
9276692c8bSGreg Roach     */
937bb2eb25SGreg Roach    protected function monthNameNominativeCase(int $month, bool $leap_year): string
94c1010edaSGreg Roach    {
95a25f0a04SGreg Roach        static $translated_month_names;
96a25f0a04SGreg Roach
97a25f0a04SGreg Roach        if ($translated_month_names === null) {
9813abd6f3SGreg Roach            $translated_month_names = [
99a25f0a04SGreg Roach                0  => '',
100bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
101bbb76c12SGreg Roach                1  => I18N::translateContext('NOMINATIVE', 'Vendemiaire'),
102bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
103bbb76c12SGreg Roach                2  => I18N::translateContext('NOMINATIVE', 'Brumaire'),
104bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
105bbb76c12SGreg Roach                3  => I18N::translateContext('NOMINATIVE', 'Frimaire'),
106bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
107bbb76c12SGreg Roach                4  => I18N::translateContext('NOMINATIVE', 'Nivose'),
108bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
109bbb76c12SGreg Roach                5  => I18N::translateContext('NOMINATIVE', 'Pluviose'),
110bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
111bbb76c12SGreg Roach                6  => I18N::translateContext('NOMINATIVE', 'Ventose'),
112bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
113bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
114bbb76c12SGreg Roach                7  => I18N::translateContext('NOMINATIVE', 'Germinal'),
115bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
116bbb76c12SGreg Roach                8  => I18N::translateContext('NOMINATIVE', 'Floreal'),
117bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
118bbb76c12SGreg Roach                9  => I18N::translateContext('NOMINATIVE', 'Prairial'),
119bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
120bbb76c12SGreg Roach                10 => I18N::translateContext('NOMINATIVE', 'Messidor'),
121bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
122bbb76c12SGreg Roach                11 => I18N::translateContext('NOMINATIVE', 'Thermidor'),
123bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
124bbb76c12SGreg Roach                12 => I18N::translateContext('NOMINATIVE', 'Fructidor'),
125bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
126bbb76c12SGreg Roach                13 => I18N::translateContext('NOMINATIVE', 'jours complementaires'),
12713abd6f3SGreg Roach            ];
128a25f0a04SGreg Roach        }
129a25f0a04SGreg Roach
1307bb2eb25SGreg Roach        return $translated_month_names[$month];
131a25f0a04SGreg Roach    }
132a25f0a04SGreg Roach
13376692c8bSGreg Roach    /**
13476692c8bSGreg Roach     * Full month name in genitive case.
13576692c8bSGreg Roach     *
1367bb2eb25SGreg Roach     * @param int  $month
13776692c8bSGreg Roach     * @param bool $leap_year Some calendars use leap months
13876692c8bSGreg Roach     *
13976692c8bSGreg Roach     * @return string
14076692c8bSGreg Roach     */
1417bb2eb25SGreg Roach    protected function monthNameGenitiveCase(int $month, bool $leap_year): string
142c1010edaSGreg Roach    {
143a25f0a04SGreg Roach        static $translated_month_names;
144a25f0a04SGreg Roach
145a25f0a04SGreg Roach        if ($translated_month_names === null) {
14613abd6f3SGreg Roach            $translated_month_names = [
147a25f0a04SGreg Roach                0  => '',
148bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
149bbb76c12SGreg Roach                1  => I18N::translateContext('GENITIVE', 'Vendemiaire'),
150bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
151bbb76c12SGreg Roach                2  => I18N::translateContext('GENITIVE', 'Brumaire'),
152bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
153bbb76c12SGreg Roach                3  => I18N::translateContext('GENITIVE', 'Frimaire'),
154bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
155bbb76c12SGreg Roach                4  => I18N::translateContext('GENITIVE', 'Nivose'),
156bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
157bbb76c12SGreg Roach                5  => I18N::translateContext('GENITIVE', 'Pluviose'),
158bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
159bbb76c12SGreg Roach                6  => I18N::translateContext('GENITIVE', 'Ventose'),
160bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
161bbb76c12SGreg Roach                7  => I18N::translateContext('GENITIVE', 'Germinal'),
162bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
163bbb76c12SGreg Roach                8  => I18N::translateContext('GENITIVE', 'Floreal'),
164bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
165bbb76c12SGreg Roach                9  => I18N::translateContext('GENITIVE', 'Prairial'),
166bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
167bbb76c12SGreg Roach                10 => I18N::translateContext('GENITIVE', 'Messidor'),
168bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
169bbb76c12SGreg Roach                11 => I18N::translateContext('GENITIVE', 'Thermidor'),
170bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
171bbb76c12SGreg Roach                12 => I18N::translateContext('GENITIVE', 'Fructidor'),
172bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
173bbb76c12SGreg Roach                13 => I18N::translateContext('GENITIVE', 'jours complementaires'),
17413abd6f3SGreg Roach            ];
175a25f0a04SGreg Roach        }
176a25f0a04SGreg Roach
1777bb2eb25SGreg Roach        return $translated_month_names[$month];
178a25f0a04SGreg Roach    }
179a25f0a04SGreg Roach
18076692c8bSGreg Roach    /**
18176692c8bSGreg Roach     * Full month name in locative case.
18276692c8bSGreg Roach     *
1837bb2eb25SGreg Roach     * @param int  $month
18476692c8bSGreg Roach     * @param bool $leap_year Some calendars use leap months
18576692c8bSGreg Roach     *
18676692c8bSGreg Roach     * @return string
18776692c8bSGreg Roach     */
1887bb2eb25SGreg Roach    protected function monthNameLocativeCase(int $month, bool $leap_year): string
189c1010edaSGreg Roach    {
190a25f0a04SGreg Roach        static $translated_month_names;
191a25f0a04SGreg Roach
192a25f0a04SGreg Roach        if ($translated_month_names === null) {
19313abd6f3SGreg Roach            $translated_month_names = [
194a25f0a04SGreg Roach                0  => '',
195bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
196bbb76c12SGreg Roach                1  => I18N::translateContext('LOCATIVE', 'Vendemiaire'),
197bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
198bbb76c12SGreg Roach                2  => I18N::translateContext('LOCATIVE', 'Brumaire'),
199bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
200bbb76c12SGreg Roach                3  => I18N::translateContext('LOCATIVE', 'Frimaire'),
201bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
202bbb76c12SGreg Roach                4  => I18N::translateContext('LOCATIVE', 'Nivose'),
203bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
204bbb76c12SGreg Roach                5  => I18N::translateContext('LOCATIVE', 'Pluviose'),
205bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
206bbb76c12SGreg Roach                6  => I18N::translateContext('LOCATIVE', 'Ventose'),
207bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
208bbb76c12SGreg Roach                7  => I18N::translateContext('LOCATIVE', 'Germinal'),
209bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
210bbb76c12SGreg Roach                8  => I18N::translateContext('LOCATIVE', 'Floreal'),
211bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
212bbb76c12SGreg Roach                9  => I18N::translateContext('LOCATIVE', 'Prairial'),
213bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
214bbb76c12SGreg Roach                10 => I18N::translateContext('LOCATIVE', 'Messidor'),
215bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
216bbb76c12SGreg Roach                11 => I18N::translateContext('LOCATIVE', 'Thermidor'),
217bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
218bbb76c12SGreg Roach                12 => I18N::translateContext('LOCATIVE', 'Fructidor'),
219bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
220bbb76c12SGreg Roach                13 => I18N::translateContext('LOCATIVE', 'jours complementaires'),
22113abd6f3SGreg Roach            ];
222a25f0a04SGreg Roach        }
223a25f0a04SGreg Roach
2247bb2eb25SGreg Roach        return $translated_month_names[$month];
225a25f0a04SGreg Roach    }
226a25f0a04SGreg Roach
22776692c8bSGreg Roach    /**
22876692c8bSGreg Roach     * Full month name in instrumental case.
22976692c8bSGreg Roach     *
2307bb2eb25SGreg Roach     * @param int  $month
23176692c8bSGreg Roach     * @param bool $leap_year Some calendars use leap months
23276692c8bSGreg Roach     *
23376692c8bSGreg Roach     * @return string
23476692c8bSGreg Roach     */
2357bb2eb25SGreg Roach    protected function monthNameInstrumentalCase(int $month, bool $leap_year): string
236c1010edaSGreg Roach    {
237a25f0a04SGreg Roach        static $translated_month_names;
238a25f0a04SGreg Roach
239a25f0a04SGreg Roach        if ($translated_month_names === null) {
24013abd6f3SGreg Roach            $translated_month_names = [
241a25f0a04SGreg Roach                0  => '',
242bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
243bbb76c12SGreg Roach                1  => I18N::translateContext('INSTRUMENTAL', 'Vendemiaire'),
244bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
245bbb76c12SGreg Roach                2  => I18N::translateContext('INSTRUMENTAL', 'Brumaire'),
246bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
247bbb76c12SGreg Roach                3  => I18N::translateContext('INSTRUMENTAL', 'Frimaire'),
248bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
249bbb76c12SGreg Roach                4  => I18N::translateContext('INSTRUMENTAL', 'Nivose'),
250bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
251bbb76c12SGreg Roach                5  => I18N::translateContext('INSTRUMENTAL', 'Pluviose'),
252bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
253bbb76c12SGreg Roach                6  => I18N::translateContext('INSTRUMENTAL', 'Ventose'),
254bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
255bbb76c12SGreg Roach                7  => I18N::translateContext('INSTRUMENTAL', 'Germinal'),
256bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
257bbb76c12SGreg Roach                8  => I18N::translateContext('INSTRUMENTAL', 'Floreal'),
258bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
259bbb76c12SGreg Roach                9  => I18N::translateContext('INSTRUMENTAL', 'Prairial'),
260bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
261bbb76c12SGreg Roach                10 => I18N::translateContext('INSTRUMENTAL', 'Messidor'),
262bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
263bbb76c12SGreg Roach                11 => I18N::translateContext('INSTRUMENTAL', 'Thermidor'),
264bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
265bbb76c12SGreg Roach                12 => I18N::translateContext('INSTRUMENTAL', 'Fructidor'),
266bbb76c12SGreg Roach                /* I18N: a month in the French republican calendar */
267bbb76c12SGreg Roach                13 => I18N::translateContext('INSTRUMENTAL', 'jours complementaires'),
26813abd6f3SGreg Roach            ];
269a25f0a04SGreg Roach        }
270a25f0a04SGreg Roach
2717bb2eb25SGreg Roach        return $translated_month_names[$month];
272a25f0a04SGreg Roach    }
273a25f0a04SGreg Roach
27476692c8bSGreg Roach    /**
27576692c8bSGreg Roach     * Abbreviated month name
27676692c8bSGreg Roach     *
2777bb2eb25SGreg Roach     * @param int  $month
27876692c8bSGreg Roach     * @param bool $leap_year Some calendars use leap months
27976692c8bSGreg Roach     *
28076692c8bSGreg Roach     * @return string
28176692c8bSGreg Roach     */
2827bb2eb25SGreg Roach    protected function monthNameAbbreviated(int $month, bool $leap_year): string
283c1010edaSGreg Roach    {
2847bb2eb25SGreg Roach        return $this->monthNameNominativeCase($month, $leap_year);
285a25f0a04SGreg Roach    }
286a25f0a04SGreg Roach
28776692c8bSGreg Roach    /**
28876692c8bSGreg Roach     * Full day of the week
28976692c8bSGreg Roach     *
29076692c8bSGreg Roach     * @param int $day_number
29176692c8bSGreg Roach     *
29276692c8bSGreg Roach     * @return string
29376692c8bSGreg Roach     */
294fe11e66dSGreg Roach    public function dayNames(int $day_number): string
295c1010edaSGreg Roach    {
296a25f0a04SGreg Roach        static $translated_day_names;
297a25f0a04SGreg Roach
298a25f0a04SGreg Roach        if ($translated_day_names === null) {
29913abd6f3SGreg Roach            $translated_day_names = [
300bbb76c12SGreg Roach                /* I18N: The first day in the French republican calendar */
301bbb76c12SGreg Roach                0 => I18N::translate('Primidi'),
302bbb76c12SGreg Roach                /* I18N: The second day in the French republican calendar */
303bbb76c12SGreg Roach                1 => I18N::translate('Duodi'),
304bbb76c12SGreg Roach                /* I18N: The third day in the French republican calendar */
305bbb76c12SGreg Roach                2 => I18N::translate('Tridi'),
306bbb76c12SGreg Roach                /* I18N: The fourth day in the French republican calendar */
307bbb76c12SGreg Roach                3 => I18N::translate('Quartidi'),
308bbb76c12SGreg Roach                /* I18N: The fifth day in the French republican calendar */
309bbb76c12SGreg Roach                4 => I18N::translate('Quintidi'),
310bbb76c12SGreg Roach                /* I18N: The sixth day in the French republican calendar */
311bbb76c12SGreg Roach                5 => I18N::translate('Sextidi'),
312bbb76c12SGreg Roach                /* I18N: The seventh day in the French republican calendar */
313bbb76c12SGreg Roach                6 => I18N::translate('Septidi'),
314bbb76c12SGreg Roach                /* I18N: The eighth day in the French republican calendar */
315bbb76c12SGreg Roach                7 => I18N::translate('Octidi'),
316bbb76c12SGreg Roach                /* I18N: The ninth day in the French republican calendar */
317bbb76c12SGreg Roach                8 => I18N::translate('Nonidi'),
318bbb76c12SGreg Roach                /* I18N: The tenth day in the French republican calendar */
319bbb76c12SGreg Roach                9 => I18N::translate('Decidi'),
32013abd6f3SGreg Roach            ];
321a25f0a04SGreg Roach        }
322a25f0a04SGreg Roach
323a25f0a04SGreg Roach        return $translated_day_names[$day_number];
324a25f0a04SGreg Roach    }
325a25f0a04SGreg Roach
32676692c8bSGreg Roach    /**
32776692c8bSGreg Roach     * Abbreviated day of the week
32876692c8bSGreg Roach     *
32976692c8bSGreg Roach     * @param int $day_number
33076692c8bSGreg Roach     *
33176692c8bSGreg Roach     * @return string
33276692c8bSGreg Roach     */
333fe11e66dSGreg Roach    protected function dayNamesAbbreviated(int $day_number): string
334c1010edaSGreg Roach    {
33517920f94SGreg Roach        return $this->dayNames($day_number);
336a25f0a04SGreg Roach    }
337a25f0a04SGreg Roach
33876692c8bSGreg Roach    /**
33976692c8bSGreg Roach     * Generate the %Y format for a date.
34076692c8bSGreg Roach     *
34176692c8bSGreg Roach     * @return string
34276692c8bSGreg Roach     */
343fe11e66dSGreg Roach    protected function formatLongYear(): string
344c1010edaSGreg Roach    {
3454ff9827fSGreg Roach        return 'An ' . $this->roman_numerals_service->numberToRomanNumerals($this->year);
346a25f0a04SGreg Roach    }
347a25f0a04SGreg Roach}
348