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