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