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