'fr', 'en-US' => 'en', 'es-ES' => 'es', 'pt-PT' => 'pt', 'it-IT' => 'it', 'de-DE' => 'de', 'ro-RO' => 'ro', 'sv-SE' => 'sv', 'da-DK' => 'da', ); protected $siteUrls = array( 'fr' => "https://icalendrier.fr/", 'en' => "https://icalendars.net/", 'es' => "https://icalendario.net/", 'pt' => "https://icalendario.pt/", 'pt-BR' => "https://icalendario.br.com/", 'it' => "https://icalendario.it/", 'de' => "https://ikalender.org/", 'ro' => "https://www.noutati-ortodoxe.ro/calendar-ortodox/", 'en-GB' => "https://icalendar.co.uk/", 'sv' => "https://ikalendrar.se/", 'da' => "https://ikalender.dk/", ); /** Site titles (config/websites.php), used as the credit line of the modern layout. */ protected $siteLabels = array( 'fr' => "iCalendrier", 'en' => "iCalendars", 'es' => "iCalendario", 'pt' => "iCalendário", 'pt-BR' => "iCalendario", 'it' => "iCalendario", 'de' => "iKalender", 'ro' => "noutati-ortodoxe.ro", 'en-GB' => "iCalendar", 'sv' => "iKalendrar", 'da' => "iKalender", ); protected $todayLabels = array( 'fr' => "Aujourd'hui", 'en' => "Today", 'es' => "Hoy en día", 'pt' => "Hoje", 'pt-BR' => "Hoje", 'it' => "Oggi", 'de' => "Heute", 'ro' => "Astăzi", 'en-GB' => "Today", 'sv' => "Idag", 'da' => "I dag", ); protected $localDays = array( 'fr' => array( 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche', ), 'en' => array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', ), 'es' => array( 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo', ), 'pt' => array( 'Segunda-feira', 'Terca-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado', 'Domingo', ), 'pt-BR' => array( 'Segunda-feira', 'Terca-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado', 'Domingo', ), 'it' => array( 'Lunedí', 'Martedí', 'Mercoledí', 'Giovedì', 'Venerdí', 'Sabato', 'Domenica', ), 'de' => array( 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag', ), 'ro' => array( 'Luni', 'Marți', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă', 'Duminică', ), 'en-GB' => array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', ), 'sv' => array( 'Måndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lördag', 'Söndag', ), 'da' => array( 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag', 'Søndag', ), ); protected $shortLocalDays = array( 'fr' => array( 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche', ), 'en' => array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', ), 'es' => array( 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado', 'Domingo', ), 'pt' => array( 'Seg.-feira', 'Terca-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado', 'Domingo', ), 'pt-BR' => array( 'Seg.-feira', 'Terca-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado', 'Domingo', ), 'it' => array( 'Lunedí', 'Martedí', 'Mercoledí', 'Giovedì', 'Venerdí', 'Sabato', 'Domenica', ), 'de' => array( 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag', ), 'ro' => array( 'Luni', 'Marți', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă', 'Duminică', ), 'en-GB' => array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', ), 'sv' => array( 'Måndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lördag', 'Söndag', ), 'da' => array( 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag', 'Søndag', ), ); protected $weekLabels = array( 'fr' => "Semaine", 'en' => "Week", 'es' => "Semana", 'pt' => "Semana", 'pt-BR' => "Semana", 'it' => "Settimana", 'de' => "Woche", 'ro' => "Săptămâna", 'en-GB' => "Week", 'sv' => "Vecka", 'da' => "Uge", ); protected $shortWeekLabels = array( 'fr' => "Sem.", 'en' => "Week", 'es' => "Sem.", 'pt' => "Sem.", 'pt-BR' => "Sem.", 'it' => "Sett.", 'de' => "Wo.", 'ro' => "Săpt.", 'en-GB' => "Week", 'sv' => "V.", 'da' => "Uge", ); protected $shortMonthLabels = array( 'fr' => array( 'Jan.', 'Fév.', 'Mars', 'Avr.', 'Mai', 'Juin', 'Juil.', 'Août', 'Sep.', 'Oct.', 'Nov.', 'Déc.' ), 'en' => array( 'Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'June', 'July', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.' ), 'es' => array( 'Ene.', 'Feb.', 'Mar.', 'Abril', 'Mayo', 'Junio', 'Julio', 'Ago.', 'Sep.', 'Oct.', 'Nov.', 'Dic.' ), 'pt' => array( 'Jan.', 'Fev.', 'Mar.', 'Abr.', 'Maio', 'Jun.', 'Jul.', 'Ago.', 'Set.', 'Out.', 'Nov.', 'Dez.' ), 'pt-BR' => array( 'Jan.', 'Fev.', 'Mar.', 'Abr.', 'Maio', 'Jun.', 'Jul.', 'Ago.', 'Set.', 'Out.', 'Nov.', 'Dez.' ), 'it' => array( 'Gen.', 'Feb.', 'Mar.', 'Apr.', 'Mag.', 'Giu.', 'Lug.', 'Ago.', 'Set.', 'Ott.', 'Nov.', 'Dic.' ), 'de' => array( 'Jan.', 'Feb.', 'März', 'Apr.', 'Mai', 'Juni', 'Juli', 'Aug.', 'Sep.', 'Okt.', 'Nov.', 'Dez.' ), 'ro' => array( 'Ian.', 'Feb.', 'Mar.', 'Apr.', 'Mai', 'Iun.', 'Iul.', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.' ), 'en-GB' => array( 'Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'June', 'July', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.' ), 'sv' => array( 'Jan.', 'Feb.', 'Mars', 'Apr.', 'Maj', 'Juni', 'Juli', 'Aug.', 'Sep.', 'Okt.', 'Nov.', 'Dec.', ), 'da' => array( 'Jan.', 'Feb.', 'Mar.', 'Apr.', 'Maj', 'Jun.', 'Jul.', 'Aug.', 'Sep.', 'Okt.', 'Nov.', 'Dec.', ), ); protected $monthLabels = array( 'fr' => array( 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre' ), 'en' => array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ), 'es' => array( 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre' ), 'pt' => array( 'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro' ), 'pt-BR' => array( 'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro' ), 'it' => array( 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre' ), 'de' => array( 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ), 'ro' => array( 'Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Iunie', 'Iulie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie' ), 'en-GB' => array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ), 'sv' => array( 'Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December', ), 'da' => array( 'Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December', ), ); protected $localMoonPhases = array( 'fr' => array( 'New Moon' => 'Nouvelle lune', 'Waxing Crescent' => 'Premier croissant', 'First Quarter' => 'Premier quartier', 'Waxing Gibbous' => 'Gibbeuse croissante', 'Full Moon' => 'Pleine lune', 'Waning Gibbous' => 'Gibbeuse décroissante', 'Third Quarter' => 'Dernier quartier', 'Waning Crescent' => 'Dernier croissant', ), 'en' => array( 'New Moon' => 'New Moon', 'Waxing Crescent' => 'Waxing Crescent', 'First Quarter' => 'First Quarter', 'Waxing Gibbous' => 'Waxing Gibbous', 'Full Moon' => 'Full Moon', 'Waning Gibbous' => 'Waning Gibbous', 'Third Quarter' => 'Third Quarter', 'Waning Crescent' => 'Waning Crescent', ), 'es' => array( 'New Moon' => 'Luna Nueva', 'Waxing Crescent' => 'Luna Nueva Visible', 'First Quarter' => 'Cuarto Creciente', 'Waxing Gibbous' => 'Luna Gibosa Creciente', 'Full Moon' => 'Luna Llena', 'Waning Gibbous' => 'Luna Gibosa Menguante', 'Third Quarter' => 'Cuarto Menguante', 'Waning Crescent' => 'Luna Menguante', ), 'pt' => array( 'New Moon' => 'Lua nova', 'Waxing Crescent' => 'Lua crescente', 'First Quarter' => 'Quarto Crescente', 'Waxing Gibbous' => 'Lua crescente convexa', 'Full Moon' => 'Lua Cheia', 'Waning Gibbous' => 'Lua minguante convexa', 'Third Quarter' => 'Quarto Minguante', 'Waning Crescent' => 'Lua minguante', ), 'pt-BR' => array( 'New Moon' => 'Lua nova', 'Waxing Crescent' => 'Lua crescente', 'First Quarter' => 'Quarto Crescente', 'Waxing Gibbous' => 'Lua crescente convexa', 'Full Moon' => 'Lua Cheia', 'Waning Gibbous' => 'Lua minguante convexa', 'Third Quarter' => 'Quarto Minguante', 'Waning Crescent' => 'Lua minguante', ), 'it' => array( 'New Moon' => 'Luna nuova', 'Waxing Crescent' => 'Luna crescente', 'First Quarter' => 'Primo quarto', 'Waxing Gibbous' => 'Gibbosa crescente', 'Full Moon' => 'Luna piena', 'Waning Gibbous' => 'Gibbosa calante', 'Third Quarter' => 'Ultimo quarto', 'Waning Crescent' => 'Luna calante', ), 'de' => array( 'New Moon' => 'Neumond', 'Waxing Crescent' => 'Erstes Viertel', 'First Quarter' => 'Zunehmender Halbmond', 'Waxing Gibbous' => 'Zweites Viertel', 'Full Moon' => 'Vollmond', 'Waning Gibbous' => 'Drittes Viertel', 'Third Quarter' => 'Abnehmender Halbmond', 'Waning Crescent' => 'Letztes Viertel', ), 'ro' => array( 'New Moon' => 'Lună nouă', 'Waxing Crescent' => 'Prima creștere', 'First Quarter' => 'Primul pătrar', 'Waxing Gibbous' => 'Lună în creștere', 'Full Moon' => 'Lună plină', 'Waning Gibbous' => 'Lună în descreștere', 'Third Quarter' => 'Al treilea pătrar', 'Waning Crescent' => 'Ultima creștere', ), 'en-GB' => array( 'New Moon' => 'New Moon', 'Waxing Crescent' => 'Waxing Crescent', 'First Quarter' => 'First Quarter', 'Waxing Gibbous' => 'Waxing Gibbous', 'Full Moon' => 'Full Moon', 'Waning Gibbous' => 'Waning Gibbous', 'Third Quarter' => 'Last Quarter', 'Waning Crescent' => 'Waning Crescent', ), 'sv' => array( 'New Moon' => 'Nymåne', 'Waxing Crescent' => 'Tilltagande skära', 'First Quarter' => 'Första kvarteret', 'Waxing Gibbous' => 'Tilltagande gibbeus', 'Full Moon' => 'Fullmåne', 'Waning Gibbous' => 'Avtagande gibbeus', 'Third Quarter' => 'Sista kvarteret', 'Waning Crescent' => 'Avtagande skära', ), 'da' => array( 'New Moon' => 'Nymåne', 'Waxing Crescent' => 'Tiltagende månesegl', 'First Quarter' => 'Første kvarter', 'Waxing Gibbous' => 'Tiltagende måne', 'Full Moon' => 'Fuldmåne', 'Waning Gibbous' => 'Aftagende måne', 'Third Quarter' => 'Sidste kvarter', 'Waning Crescent' => 'Aftagende månesegl', ), ); /** * @param string $lang * @param string|int $timezone PHP timezone identifier; 0, '0' or '' keep the server default * @param DateTimeInterface|int|null $now Reference time (tests); defaults to now */ public function __construct($lang = 'en', $timezone = 0, DateTimeInterface|int|null $now = null) { $lang = $this->aliases[$lang] ?? $lang; if ( ! in_array($lang, $this->langs, true)) { $lang = "en"; // Default En } $this->lang = $lang; // The zone only affects this instance's reference time; global PHP state is left alone. // null means "not requested": an injected $now keeps its own zone, anything else uses the server default. $zone = self::timezone($timezone); if ($now instanceof DateTimeInterface) { $this->now = DateTimeImmutable::createFromInterface($now); if (null !== $zone) { $this->now = $this->now->setTimezone($zone); } } elseif (is_int($now)) { $this->now = (new DateTimeImmutable('@' . $now))->setTimezone($zone ?? new DateTimeZone(date_default_timezone_get())); } else { $this->now = new DateTimeImmutable('now', $zone); } $this->nameDay = new NameDay(); } /** * @param string|int $timezone */ private static function timezone($timezone): ?DateTimeZone { if ( ! is_string($timezone) || '' === $timezone || '0' === $timezone) { return null; } try { return new DateTimeZone($timezone); } catch (Exception $e) { return null; // Unknown identifier: server default. } } /** * @param array $parameters showLink, bgColor, style, showNameDay (default on) * * @return string */ public function iCalendrierComp($parameters = []) { $html = ''; $showLink = isset($parameters['showLink']) ? (bool)$parameters['showLink'] : false; $showNameDay = $this->showNameDay($parameters); $bgColor = isset($parameters['bgColor']) ? $this->secureParam($parameters['bgColor']) : false; $styleClassname = isset($parameters['style']) && 'default' !== $parameters['style'] ? ' ' . $this->secureParam($parameters['style']) : ''; $html .= '
'; $html .= '
'; if ($bgColor) { $html .= '
'; } else { $html .= '
'; } $html .= '
'; if ($showLink) { $html .= '' . $this->todayLabels[$this->lang] . ''; } else { $html .= '' . $this->todayLabels[$this->lang] . ''; } $html .= '
'; $html .= '
'; $html .= '
'; $html .= ''; $html .= $this->shortLocalDays[$this->lang][$this->now->format('N') - 1]; $html .= " - "; $html .= $this->shortWeekLabels[$this->lang] . " " . ltrim($this->now->format('W'), '0'); $html .= ''; $day = $this->now->format('d'); $daydig1 = substr($day, 0, 1); $daydig2 = substr($day, 1, 1); $html .= ''; $html .= ''; $html .= $daydig1; $html .= ''; $html .= ''; $html .= $daydig2; $html .= ''; $html .= ''; $html .= ''; $html .= $this->shortMonthLabels[$this->lang][$this->now->format('n') - 1]; $html .= ''; if ($showNameDay) { $html .= ''; $html .= $this->nameDay->today($this->lang, (int)$this->now->format('n'), (int)$this->now->format('j')); $html .= ''; } $html .= ''; $html .= $this->getMoonSide(); $html .= ''; $html .= '
'; $html .= '
'; $html .= '
'; $html .= '
'; $html .= '
'; return $html; } /** * Wide calendar * * @param $parameters * * @return string */ public function iCalendrierWide($parameters) { $html = ""; $showLink = isset($parameters['showLink']) ? (bool)$parameters['showLink'] : false; $showNameDay = $this->showNameDay($parameters); $bgColor = isset($parameters['bgColor']) ? $this->secureParam($parameters['bgColor']) : false; $styleClassname = isset($parameters['style']) && 'default' !== $parameters['style'] ? ' ' . $this->secureParam($parameters['style']) : ''; if ($bgColor) { $html .= '
'; } else { $html .= '
'; } $html .= '
'; $html .= ''; if ($showLink) { $html .= '' . $this->todayLabels[$this->lang] . ''; } else { $html .= '' . $this->todayLabels[$this->lang] . ''; } $html .= ''; $html .= ''; $html .= $this->shortLocalDays[$this->lang][$this->now->format('N') - 1]; $html .= ''; $html .= '' . $this->now->format('d') . ''; $html .= ''; $html .= $this->monthLabels[$this->lang][$this->now->format('n') - 1]; $html .= ''; $html .= ''; $html .= $this->weekLabels[$this->lang] . " " . ltrim($this->now->format('W'), '0'); if ($showNameDay) { $html .= ' | '; $html .= $this->nameDay->today($this->lang, (int)$this->now->format('n'), (int)$this->now->format('j')); } $html .= ''; $html .= ''; $html .= $this->getMoonSide(); $html .= ''; $html .= '
'; $html .= '
'; return $html; } /** * Modern layout (v2), same markup and classes as the widget on the iCalendrier sites. * * @param array $parameters showLink, bgColor, style, showMoon (default on), showNameDay (default on) * * @return string */ public function iCalendrierModern($parameters = []) { $showLink = isset($parameters['showLink']) ? (bool)$parameters['showLink'] : false; $showMoon = ! isset($parameters['showMoon']) || (bool)$parameters['showMoon']; $showNameDay = $this->showNameDay($parameters); $bgColor = isset($parameters['bgColor']) ? $this->secureParam($parameters['bgColor']) : false; $styleClassname = isset($parameters['style']) && 'default' !== $parameters['style'] ? ' ' . $this->secureParam($parameters['style']) : ''; $lang = $this->lang; $html = '
'; $html .= $bgColor ? '
' : '
'; if ($showLink) { $html .= '' . $this->siteLabels[$lang] . ''; } $html .= '
' . $this->dateLabel($this->localDays[$lang][$this->now->format('N') - 1]) . '
'; $html .= '
' . $this->now->format('d') . '
'; $html .= '
' . $this->dateLabel($this->monthLabels[$lang][$this->now->format('n') - 1]) . ' ' . $this->now->format('Y') . '
'; $html .= '
'; $html .= ''; $html .= ''; $html .= '
'; return $html; } /** Name days are a Latin-country habit; Northern sites can switch them off. Default on. */ private function showNameDay(array $parameters): bool { return ! isset($parameters['showNameDay']) || (bool)$parameters['showNameDay']; } /** Day or month name in the casing the current language uses in running text. */ private function dateLabel(string $label): string { return in_array($this->lang, $this->lowercaseDates, true) ? mb_strtolower($label) : $label; } /** * Moon for the night that matters: before 7am the night in progress (last midnight), * from 7am the coming one (next midnight). */ protected function moon(): Solaris_MoonPhase { require_once(dirname(__FILE__) . '/Solaris/MoonPhase.php'); $midnight = $this->now->setTime(0, 0); if ((int)$this->now->format('G') >= 7) { $midnight = $midnight->add(new DateInterval('P1D')); } return new Solaris_MoonPhase((int)$midnight->format('U')); } /** * Frame 0-7 in the 8-image moon sprite of the modern layout (same formula as the site widget). */ protected function moonFrame(Solaris_MoonPhase $moon): int { return (int)floor(($moon->phase() + 0.0625) * 8) % 8; } /** * Select the moon character * @return string */ protected function getMoonSide() { $moon = $this->moon(); $phase = $moon->phase(); // Utilisation de la font // 29 "phases" pour correspondre à la font $moonCharacters = array(0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', '@', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0); $totalCharacters = count($moonCharacters); $step = 1 / ($totalCharacters - 1); if ($phase < $step / 2) { $index = 0; } elseif ($phase > (1 - $step / 2)) { $index = 28; } else { for ($i = 1; $i <= 27; $i++) { // Passage dans l'interval qui entoure l'illustration if ($phase >= ($step / 2 + ($i - 1) * $step) && $phase < ($step / 2 + $i * $step)) { $index = $i; } } } $html = '' . $moonCharacters[$index] . ''; $html .= $this->localMoonPhases[$this->lang][$moon->phase_name()]; return $html; } /** * @param string $param * * @return string */ private function secureParam(string $param) { return htmlentities(str_replace(["'", '"'], ['', ''], $param)); } }