diff --git a/src/NodaTimeAutotranslater.php b/src/NodaTimeAutotranslater.php index 8f27a2b..9c0245a 100644 --- a/src/NodaTimeAutotranslater.php +++ b/src/NodaTimeAutotranslater.php @@ -18,6 +18,9 @@ final class NodaTimeAutotranslater { const TRANSLATABLE_NOT = 0; const TRANSLATABLE_AS_MONTH_DAY = 1; const TRANSLATABLE_AS_YEAR_WITH_SUFFIX = 2; + const TRANSLATABLE_SINCE_START = 3; + const TRANSLATABLE_UNTIL_END = 4; + const TRANSLATABLE_ONLY_YEAR = 5; const LANGS_TO_LOCALES = [ 'ar' => 'ar_SY.utf8', @@ -144,6 +147,56 @@ final class NodaTimeAutotranslater { 'zh' => '%s', ]; + const LANGS_SINCE_START_FORMAT_YEAR = [ + 'ar' => '%s-', + 'de' => 'Seit %s', + 'en' => 'Since %s', + 'es' => 'Desde %s', + 'fa' => '%s-', + 'fr' => 'Depuis %s', + 'hu' => '%s-től', + 'id' => 'Sejak %s', + 'it' => 'Dal %s', + 'ka' => '%s წლიდან', + 'ko' => '%s부터', + 'pl' => 'Desde %s', + 'pt' => '%s dC', + 'ro' => 'Din %s', + 'ru' => 'С %s г.', + 'ta' => '%s முதல்', + 'tl' => 'Mula noong %s', + 'tr' => '%s-', + + // Languages that don't really need a specific locale + 'ja' => '%s以来', + 'zh' => '自%s以來', + ]; + + const LANGS_UNTIL_START_FORMAT_YEAR = [ + 'ar' => '-%s', + 'de' => 'Bis %s', + 'en' => 'Until %s', + 'es' => 'Hasta %s', + 'fa' => '-%s', + 'fr' => 'Jusqu\'en %s', + 'hu' => '%s-ig', + 'id' => 'Sampai %s', + 'it' => 'Fino al %s', + 'ka' => '%s წლამდე', + 'ko' => '%s까지', + 'pl' => 'do %s roku', + 'pt' => 'até %s', + 'ro' => 'până în %s', + 'ru' => 'до %s г.', + 'ta' => '%s வரை', + 'tl' => 'Hanggang %s', + 'tr' => '%s-', + + // Languages that don't really need a specific locale + 'ja' => '%sまで', + 'zh' => '直到%s', + ]; + /** @var MDMysqli */ private MDMysqli $_mysqli_noda; /** @var integer */ @@ -163,12 +216,21 @@ final class NodaTimeAutotranslater { */ public static function check_translatability(string $zeit_beginn, string $zeit_ende, string $zeit_zaehlzeit_monat):int { + if (intval($zeit_beginn) > 1000 and $zeit_ende === "?") { + return self::TRANSLATABLE_SINCE_START; + } + if (intval($zeit_ende) > 1000 and $zeit_beginn === "?") { + return self::TRANSLATABLE_UNTIL_END; + } if (intval($zeit_ende) >= 0 && intval($zeit_beginn) < 0) { return self::TRANSLATABLE_NOT; } if (intval($zeit_ende) < 0 && intval($zeit_beginn) < 0 || intval($zeit_ende) < 1000) { return self::TRANSLATABLE_AS_YEAR_WITH_SUFFIX; } + if ($zeit_ende === $zeit_beginn and trim($zeit_zaehlzeit_monat, ", .0") === "") { + return self::TRANSLATABLE_ONLY_YEAR; + } // Conditions speaking against translatability. if (trim($zeit_zaehlzeit_monat, ", .0") === "") { return self::TRANSLATABLE_NOT; @@ -179,16 +241,14 @@ final class NodaTimeAutotranslater { } /** - * Translated years or timespans below 1000 CE. + * Gets suffix mode for years with suffix. * - * @param array $timeInfo Time information. + * @param integer $start Start year. + * @param integer $end End year. * - * @return void + * @return integer */ - public function translateYearsWithSuffix(array $timeInfo):void { - - $start = intval($timeInfo['zeit_beginn']); - $end = intval($timeInfo['zeit_ende']); + public static function getSuffixModeForYearsWSuffix(int $start, int $end):int { if ($start < 0 && $end < 0) { $suffixMode = 2; // 2; // " v. Chr."; @@ -196,8 +256,51 @@ final class NodaTimeAutotranslater { else if ($end < 1000) { $suffixMode = 1; // " n. Chr."; } - else $suffixMode = 0; + else $suffixMode = 0; // Times larger than 1000 n. Chr. + return $suffixMode; + + } + + /** + * Applies suffix format to a time string. + * + * @param string $tLang Two digit ANSI language code. + * @param string $timeName Time name. + * @param integer $suffixMode Suffix mode. + * + * @return string + */ + public static function applyBcBceFormat(string $tLang, string $timeName, int $suffixMode):string { + + switch ($suffixMode) { + case 0: + return $timeName; + case 1: + return sprintf(self::LANGS_TO_CE_FORMAT[$tLang], $timeName); + case 2: + return sprintf(self::LANGS_TO_BCE_FORMAT[$tLang], $timeName); + default: + throw new Exception("Unknown case encountered for time translations."); + } + + } + + /** + * Translated years or timespans below 1000 CE. + * + * @param array $timeInfo Time information. + * + * @return array + */ + public function translateYearsWithSuffix(array $timeInfo):array { + + $start = intval($timeInfo['zeit_beginn']); + $end = intval($timeInfo['zeit_ende']); + + $suffixMode = self::getSuffixModeForYearsWSuffix($start, $end); + + $output = []; foreach (self::LANGS_TO_CE_FORMAT as $tLang => $ceFormat) { if ($start === $end) { @@ -205,43 +308,112 @@ final class NodaTimeAutotranslater { } else $year = sprintf(self::LANGS_YEARSPAN_FORMAT[$tLang], (string)abs($start), (string)abs($end)); - switch ($suffixMode) { - case 0: - $timeName = $year; - break; - case 1: - $timeName = sprintf($ceFormat, $year); - break; - case 2: - $timeName = sprintf(self::LANGS_TO_BCE_FORMAT[$tLang], $year); - break; - default: - throw new Exception("Unknown case encountered for time translations."); - } - - $this->_insertStmt->bind_param("iss", $this->_znum, $tLang, $timeName); - $this->_insertStmt->execute(); + $output[$tLang] = self::applyBcBceFormat($tLang, $year, $suffixMode); } + return $output; } /** - * Runs autotranslater. + * Translated only years: 1994. * * @param array $timeInfo Time information. * - * @return void + * @return array */ - public function translate(array $timeInfo):void { + public static function translateYearOnly(array $timeInfo):array { + + $start = intval($timeInfo['zeit_beginn']); + $output = []; + + foreach (self::LANGS_SINGLE_YEAR_FORMAT as $tLang => $format) { + $output[$tLang] = sprintf($format, (string)abs($start)); + } + return $output; + + } + + /** + * Translated years or timespans below 1000 CE. + * + * @param array $timeInfo Time information. + * + * @return array + */ + public static function translateYearsSinceStart(array $timeInfo):array { + + $start = intval($timeInfo['zeit_beginn']); + + $innerTimeInfo = $timeInfo; + $innerTimeInfo['zeit_ende'] = $timeInfo['zeit_beginn']; + $output = []; + + foreach (self::LANGS_SINCE_START_FORMAT_YEAR as $tLang => $format) { + + $dateAlone = self::getTranslations($innerTimeInfo)[$tLang]; + + $timeName = sprintf($format, $dateAlone); + $output[$tLang] = $timeName; + + } + return $output; + + } + + /** + * Translated years or timespans below 1000 CE. + * + * @param array $timeInfo Time information. + * + * @return array + */ + public static function translateYearsUntilEnd(array $timeInfo):array { + + $end = intval($timeInfo['zeit_ende']); + + $innerTimeInfo = $timeInfo; + $innerTimeInfo['zeit_beginn'] = $timeInfo['zeit_ende']; + + $output = []; + foreach (self::LANGS_UNTIL_START_FORMAT_YEAR as $tLang => $format) { + + $dateAlone = self::getTranslations($innerTimeInfo)[$tLang]; + + $timeName = sprintf($format, $dateAlone); + $output[$tLang] = $timeName; + } + return $output; + + } + + /** + * Gets translations for a given entry type. + * + * @param array $timeInfo Time information. + * + * @return array + */ + public static function getTranslations(array $timeInfo):array { if (!($translation_type = self::check_translatability((string)$timeInfo['zeit_beginn'], (string)$timeInfo['zeit_ende'], (string)$timeInfo['zeit_zaehlzeit_monat']))) { throw new MDgenericInvalidInputsException("Non-translatable date"); } + if ($translation_type === self::TRANSLATABLE_ONLY_YEAR) { + return self::translateYearOnly($timeInfo); + } + + if ($translation_type === self::TRANSLATABLE_SINCE_START) { + return self::translateYearsSinceStart($timeInfo); + } + + if ($translation_type === self::TRANSLATABLE_UNTIL_END) { + return self::translateYearsUntilEnd($timeInfo); + } + if ($translation_type === self::TRANSLATABLE_AS_YEAR_WITH_SUFFIX) { - $this->translateYearsWithSuffix($timeInfo); - return; + return self::translateYearsWithSuffix($timeInfo); } if (trim((string)$timeInfo['zeit_zaehlzeit_tag'], ", .0") === "") { @@ -255,6 +427,7 @@ final class NodaTimeAutotranslater { $dateGeneral = strtotime($dateStr); + $output = []; foreach (self::LANGS_TO_LOCALES as $tLang => $locale) { setlocale(LC_TIME, $locale); @@ -264,9 +437,28 @@ final class NodaTimeAutotranslater { $tLangValue = strftime(getDateFormatByLang($tLang), $dateGeneral ?: 0); } + $output[$tLang] = $tLangValue; + + } + + return $output; + + } + + /** + * Runs autotranslater. + * + * @param array $timeInfo Time information. + * + * @return void + */ + public function translate(array $timeInfo):void { + + $translations = self::getTranslations($timeInfo); + + foreach ($translations as $tLang => $tLangValue) { $this->_insertStmt->bind_param("iss", $this->_znum, $tLang, $tLangValue); $this->_insertStmt->execute(); - } } diff --git a/src/NodaTimeSplitter.php b/src/NodaTimeSplitter.php index 4e03601..7baeba8 100644 --- a/src/NodaTimeSplitter.php +++ b/src/NodaTimeSplitter.php @@ -545,6 +545,26 @@ final class NodaTimeSplitter { } } + // Endings beginning with a space + if (preg_match("/ (\(bis\))$/", $datum)) { + if (($spacePos = strrpos($datum, " ")) === false) { + return []; + } + if ($output = self::attempt_splitting(substr($datum, 0, $spacePos))) { + $output[0] = "?"; + return $output; + } + } + if (preg_match("/\-ig$/", $datum)) { + if (($spacePos = strrpos($datum, "-")) === false) { + return []; + } + if ($output = self::attempt_splitting(substr($datum, 0, $spacePos))) { + $output[0] = "?"; + return $output; + } + } + return []; }