diff options
49 files changed, 936 insertions, 125 deletions
diff --git a/app/Elements/DateValue.php b/app/Elements/DateValue.php index 492b181964..5e543807cc 100644 --- a/app/Elements/DateValue.php +++ b/app/Elements/DateValue.php @@ -22,11 +22,8 @@ namespace Fisharebest\Webtrees\Elements; use Fisharebest\Webtrees\Date; use Fisharebest\Webtrees\Html; use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Services\LocalizationService; use Fisharebest\Webtrees\Tree; -use function app; -use function assert; use function e; use function preg_replace_callback; use function view; @@ -59,10 +56,7 @@ class DateValue extends AbstractElement public function edit(string $id, string $name, string $value, Tree $tree): string { // Need to know if the user prefers DMY/MDY/YMD so we can validate dates properly. - $localization_service = app(LocalizationService::class); - assert($localization_service instanceof LocalizationService); - - $dmy = $localization_service->dateFormatToOrder(I18N::dateFormat()); + $dmy = I18N::language()->dateOrder(); $attributes = [ 'class' => 'form-control', diff --git a/app/Http/RequestHandlers/CalendarPage.php b/app/Http/RequestHandlers/CalendarPage.php index 85f7af40a3..16420370bd 100644 --- a/app/Http/RequestHandlers/CalendarPage.php +++ b/app/Http/RequestHandlers/CalendarPage.php @@ -23,7 +23,6 @@ use Fisharebest\Webtrees\Date; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Services\CalendarService; -use Fisharebest\Webtrees\Services\LocalizationService; use Fisharebest\Webtrees\Validator; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; @@ -38,18 +37,14 @@ class CalendarPage implements RequestHandlerInterface private CalendarService $calendar_service; - private LocalizationService $localization_service; - /** * CalendarPage constructor. * - * @param CalendarService $calendar_service - * @param LocalizationService $localization_service + * @param CalendarService $calendar_service */ - public function __construct(CalendarService $calendar_service, LocalizationService $localization_service) + public function __construct(CalendarService $calendar_service) { - $this->calendar_service = $calendar_service; - $this->localization_service = $localization_service; + $this->calendar_service = $calendar_service; } /** @@ -73,7 +68,7 @@ class CalendarPage implements RequestHandlerInterface if ($cal . $day . $month . $year === '') { // No date specified? Use the most likely calendar - $cal = $this->localization_service->calendar(I18N::locale())->gedcomCalendarEscape(); + $cal = I18N::language()->calendar()->gedcomCalendarEscape(); } // need BC to parse date diff --git a/app/Http/RequestHandlers/HelpText.php b/app/Http/RequestHandlers/HelpText.php index aad22c32a5..45f19d7c40 100644 --- a/app/Http/RequestHandlers/HelpText.php +++ b/app/Http/RequestHandlers/HelpText.php @@ -22,7 +22,6 @@ namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fisharebest\Webtrees\Auth; use Fisharebest\Webtrees\Date; use Fisharebest\Webtrees\I18N; -use Fisharebest\Webtrees\Services\LocalizationService; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; @@ -178,18 +177,6 @@ class HelpText implements RequestHandlerInterface ], ]; - private LocalizationService $localisation_service; - - /** - * HelpText constructor. - * - * @param LocalizationService $localization_service - */ - public function __construct(LocalizationService $localization_service) - { - $this->localisation_service = $localization_service; - } - /** * @param ServerRequestInterface $request * @@ -199,7 +186,7 @@ class HelpText implements RequestHandlerInterface { $topic = $request->getAttribute('topic'); - $dmy = $this->localisation_service->dateFormatToOrder(I18N::dateFormat()); + $dmy = I18N::language()->dateOrder(); switch ($topic) { case 'DATE': diff --git a/app/Http/RequestHandlers/ReportSetupPage.php b/app/Http/RequestHandlers/ReportSetupPage.php index 6f1934eb5d..e4a7a4d7dd 100644 --- a/app/Http/RequestHandlers/ReportSetupPage.php +++ b/app/Http/RequestHandlers/ReportSetupPage.php @@ -26,7 +26,6 @@ use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Module\ModuleReportInterface; use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Report\ReportParserSetup; -use Fisharebest\Webtrees\Services\LocalizationService; use Fisharebest\Webtrees\Services\ModuleService; use Fisharebest\Webtrees\Validator; use Psr\Http\Message\ResponseInterface; @@ -43,19 +42,15 @@ class ReportSetupPage implements RequestHandlerInterface { use ViewResponseTrait; - private LocalizationService $localization_service; - private ModuleService $module_service; /** * ReportEngineController constructor. * - * @param LocalizationService $localization_service - * @param ModuleService $module_service + * @param ModuleService $module_service */ - public function __construct(LocalizationService $localization_service, ModuleService $module_service) + public function __construct(ModuleService $module_service) { - $this->localization_service = $localization_service; $this->module_service = $module_service; } @@ -135,7 +130,7 @@ class ReportSetupPage implements RequestHandlerInterface case 'DATE': // Need to know if the user prefers DMY/MDY/YMD so we can validate dates properly. - $dmy = $this->localization_service->dateFormatToOrder(I18N::dateFormat()); + $dmy = I18N::language()->dateOrder(); $attributes += [ 'type' => 'text', diff --git a/app/Module/IndividualListModule.php b/app/Module/IndividualListModule.php index 9c6f3eab44..6c03164628 100644 --- a/app/Module/IndividualListModule.php +++ b/app/Module/IndividualListModule.php @@ -26,7 +26,6 @@ use Fisharebest\Webtrees\Family; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Individual; use Fisharebest\Webtrees\Registry; -use Fisharebest\Webtrees\Services\LocalizationService; use Fisharebest\Webtrees\Session; use Fisharebest\Webtrees\Tree; use Fisharebest\Webtrees\Validator; @@ -60,18 +59,6 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface protected const ROUTE_URL = '/tree/{tree}/individual-list'; - private LocalizationService $localization_service; - - /** - * IndividualListModule constructor. - * - * @param LocalizationService $localization_service - */ - public function __construct(LocalizationService $localization_service) - { - $this->localization_service = $localization_service; - } - /** * Initialization. * @@ -251,7 +238,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface ]; } } elseif ($surname !== '') { - $alpha = $this->localization_service->initialLetter($surname, I18N::locale()); // so we can highlight the initial letter + $alpha = I18N::language()->initialLetter($surname); // so we can highlight the initial letter $show_all = 'no'; if ($surname === Individual::NOMEN_NESCIO) { $legend = I18N::translateContext('Unknown surname', '…'); @@ -400,7 +387,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface echo view('lists/surnames-table', [ 'families' => $families, 'module' => $this, - 'order' => [[1, 'desc']], + 'order' => [[0, 'asc']], 'surnames' => $surns, 'tree' => $tree, ]); @@ -562,9 +549,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface */ public function surnameAlpha(Tree $tree, bool $marnm, bool $fams, LocaleInterface $locale): array { - $collation = $this->localization_service->collation($locale); - - $n_surn = $this->fieldWithCollation('n_surn', $collation); + $n_surn = $this->fieldWithCollation('n_surn'); $alphas = []; $query = DB::table('name')->where('n_file', '=', $tree->id()); @@ -575,7 +560,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface // Fetch all the letters in our alphabet, whether or not there // are any names beginning with that letter. It looks better to // show the full alphabet, rather than omitting rare letters such as X. - foreach ($this->localization_service->alphabet($locale) as $letter) { + foreach (I18N::language()->alphabet() as $letter) { $query2 = clone $query; $this->whereInitial($query2, 'n_surn', $letter, $locale); @@ -585,7 +570,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface // Now fetch initial letters that are not in our alphabet, // including "@" (for "@N.N.") and "" for no surname. - foreach ($this->localization_service->alphabet($locale) as $letter) { + foreach (I18N::language()->alphabet() as $letter) { $query->where($n_surn, 'NOT LIKE', $letter . '%'); } @@ -626,8 +611,6 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface */ public function givenAlpha(Tree $tree, string $surn, string $salpha, bool $marnm, bool $fams, LocaleInterface $locale): array { - $collation = $this->localization_service->collation($locale); - $alphas = []; $query = DB::table('name') @@ -637,7 +620,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface $this->whereMarriedName($marnm, $query); if ($surn !== '') { - $n_surn = $this->fieldWithCollation('n_surn', $collation); + $n_surn = $this->fieldWithCollation('n_surn'); $query->where($n_surn, '=', $surn); } elseif ($salpha === ',') { $query->where('n_surn', '=', ''); @@ -653,7 +636,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface // Fetch all the letters in our alphabet, whether or not there // are any names beginning with that letter. It looks better to // show the full alphabet, rather than omitting rare letters such as X - foreach ($this->localization_service->alphabet($locale) as $letter) { + foreach (I18N::language()->alphabet() as $letter) { $query2 = clone $query; $this->whereInitial($query2, 'n_givn', $letter, $locale); @@ -730,7 +713,7 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface $list = []; foreach ($query->get() as $row) { - $row->n_surn = I18N::strtoupper($row->n_surn); + $row->n_surn = strtr(I18N::strtoupper($row->n_surn), I18N::language()->equivalentLetters()); $row->total += $list[$row->n_surn][$row->n_surname] ?? 0; $list[$row->n_surn][$row->n_surname] = (int) $row->total; @@ -765,11 +748,9 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface bool $fams, LocaleInterface $locale ): Collection { - $collation = $this->localization_service->collation($locale); - // Use specific collation for name fields. - $n_givn = $this->fieldWithCollation('n_givn', $collation); - $n_surn = $this->fieldWithCollation('n_surn', $collation); + $n_givn = $this->fieldWithCollation('n_givn'); + $n_surn = $this->fieldWithCollation('n_surn'); $query = DB::table('individuals') ->join('name', static function (JoinClause $join): void { @@ -859,13 +840,12 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface * Use MySQL-specific comments so we can run these queries on other RDBMS. * * @param string $field - * @param string $collation * * @return Expression */ - protected function fieldWithCollation(string $field, string $collation): Expression + protected function fieldWithCollation(string $field): Expression { - return new Expression($field . ' /*! COLLATE ' . $collation . ' */'); + return new Expression($field . ' /*! COLLATE ' . I18N::collation() . ' */'); } /** @@ -885,10 +865,8 @@ class IndividualListModule extends AbstractModule implements ModuleListInterface string $letter, LocaleInterface $locale ): void { - $collation = $this->localization_service->collation($locale); - // Use MySQL-specific comments so we can run these queries on other RDBMS. - $field_with_collation = $this->fieldWithCollation($field, $collation); + $field_with_collation = $this->fieldWithCollation($field); switch ($locale->languageTag()) { case 'cs': diff --git a/app/Module/LanguageArabic.php b/app/Module/LanguageArabic.php index 0425b01d76..adfdb59cf1 100644 --- a/app/Module/LanguageArabic.php +++ b/app/Module/LanguageArabic.php @@ -19,6 +19,8 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Module; +use Fisharebest\ExtCalendar\ArabicCalendar; +use Fisharebest\ExtCalendar\CalendarInterface; use Fisharebest\Localization\Locale\LocaleAr; use Fisharebest\Localization\Locale\LocaleInterface; @@ -30,6 +32,26 @@ class LanguageArabic extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['ا', 'ب', 'ت', 'ث', 'ج', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز', 'س', 'ش', 'ص', 'ض', 'ط', 'ظ', 'ع', 'غ', 'ف', 'ق', 'ك', 'ل', 'م', 'ن', 'ه', 'و', 'ي', 'آ', 'ة', 'ى', 'ی']; + } + + /** + * Default calendar used by this language. + * + * @return CalendarInterface + */ + public function calendar(): CalendarInterface + { + return new ArabicCalendar(); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageBulgarian.php b/app/Module/LanguageBulgarian.php index 6de9ad320f..c03c56bc1d 100644 --- a/app/Module/LanguageBulgarian.php +++ b/app/Module/LanguageBulgarian.php @@ -30,6 +30,16 @@ class LanguageBulgarian extends AbstractModule implements ModuleLanguageInterfac use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я']; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageChineseSimplified.php b/app/Module/LanguageChineseSimplified.php index c745a9162c..f4ec471a65 100644 --- a/app/Module/LanguageChineseSimplified.php +++ b/app/Module/LanguageChineseSimplified.php @@ -30,6 +30,16 @@ class LanguageChineseSimplified extends AbstractModule implements ModuleLanguage use ModuleLanguageTrait; /** + * One of: 'DMY', 'MDY', 'YMD'. + * + * @return string + */ + public function dateOrder(): string + { + return 'YMD'; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageChineseTraditional.php b/app/Module/LanguageChineseTraditional.php index 5bd1b4d6e9..5c13a97f23 100644 --- a/app/Module/LanguageChineseTraditional.php +++ b/app/Module/LanguageChineseTraditional.php @@ -30,6 +30,16 @@ class LanguageChineseTraditional extends AbstractModule implements ModuleLanguag use ModuleLanguageTrait; /** + * One of: 'DMY', 'MDY', 'YMD'. + * + * @return string + */ + public function dateOrder(): string + { + return 'YMD'; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageCroatian.php b/app/Module/LanguageCroatian.php index badfe070b1..f2a0a7dd5e 100644 --- a/app/Module/LanguageCroatian.php +++ b/app/Module/LanguageCroatian.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleHr; use Fisharebest\Localization\Locale\LocaleInterface; +use Illuminate\Database\Query\Builder; /** * Class LanguageCroatian. @@ -30,6 +31,18 @@ class LanguageCroatian extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_croatian_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageCzech.php b/app/Module/LanguageCzech.php index b316dca751..2d31a2503a 100644 --- a/app/Module/LanguageCzech.php +++ b/app/Module/LanguageCzech.php @@ -21,6 +21,10 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleCs; use Fisharebest\Localization\Locale\LocaleInterface; +use Illuminate\Database\Query\Builder; + +use function mb_substr; +use function str_starts_with; /** * Class LanguageCzech. @@ -30,6 +34,48 @@ class LanguageCzech extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['A', 'Á', 'B', 'C', 'Č', 'D', 'Ď', 'E', 'É', 'Ě', 'F', 'G', 'H', 'CH', 'I', 'Í', 'J', 'K', 'L', 'M', 'N', 'Ň', 'O', 'Ó', 'P', 'Q', 'R', 'Ř', 'S', 'Š', 'T', 'Ť', 'U', 'Ú', 'Ů', 'V', 'W', 'X', 'Y', 'Ý', 'Z', 'Ž']; + } + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string + { + if (str_starts_with($string, 'CS')) { + return 'CS'; + } + + return mb_substr($string, 0, 1); + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_czech_ci */', 'LIKE', '\\' . $letter . '%'); + + if ($letter === 'C') { + $query->where($column . ' /*! COLLATE utf8_czech_ci */', 'NOT LIKE', 'CS%'); + } + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageDanish.php b/app/Module/LanguageDanish.php index ba81647bb6..462441e955 100644 --- a/app/Module/LanguageDanish.php +++ b/app/Module/LanguageDanish.php @@ -21,6 +21,10 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleDa; use Fisharebest\Localization\Locale\LocaleInterface; +use Illuminate\Database\Query\Builder; + +use function mb_substr; +use function str_starts_with; /** * Class LanguageDanish. @@ -30,6 +34,54 @@ class LanguageDanish extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'Æ', 'Ø', 'Å']; + } + + /** + * Some languages treat certain letter-combinations as equivalent. + * + * @return array<string,string> + */ + public function equivalentLetters(): array + { + return ['aa' => 'å', 'aA' => 'å', 'Aa' => 'Å', 'AA' => 'Å']; + } + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string + { + if (str_starts_with($string, 'AA')) { + return 'Å'; + } + + return mb_substr($string, 0, 1); + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_danish_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageDutch.php b/app/Module/LanguageDutch.php index da6fcaa1dc..103a71e9dc 100644 --- a/app/Module/LanguageDutch.php +++ b/app/Module/LanguageDutch.php @@ -22,6 +22,9 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleNl; +use function mb_substr; +use function str_starts_with; + /** * Class LanguageDutch. */ @@ -30,6 +33,32 @@ class LanguageDutch extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'IJ']; + } + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string + { + if (str_starts_with($string, 'IJ')) { + return 'IJ'; + } + + return mb_substr($string, 0, 1); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageEnglishUnitedStates.php b/app/Module/LanguageEnglishUnitedStates.php index 7741e7e126..585e43b2df 100644 --- a/app/Module/LanguageEnglishUnitedStates.php +++ b/app/Module/LanguageEnglishUnitedStates.php @@ -108,6 +108,16 @@ class LanguageEnglishUnitedStates extends AbstractModule implements ModuleLangua ]; /** + * One of: 'DMY', 'MDY', 'YMD'. + * + * @return string + */ + public function dateOrder(): string + { + return 'MDY'; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageEstonian.php b/app/Module/LanguageEstonian.php index 6385e19ca5..6418ec003f 100644 --- a/app/Module/LanguageEstonian.php +++ b/app/Module/LanguageEstonian.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleEt; use Fisharebest\Localization\Locale\LocaleInterface; +use Illuminate\Database\Query\Builder; /** * Class LanguageEstonian. @@ -30,6 +31,28 @@ class LanguageEstonian extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Š', 'Z', 'Ž', 'T', 'U', 'V', 'W', 'Õ', 'Ä', 'Ö', 'Ü', 'X', 'Y']; + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_estonian_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageFarsi.php b/app/Module/LanguageFarsi.php index 2c212b6c08..912306c172 100644 --- a/app/Module/LanguageFarsi.php +++ b/app/Module/LanguageFarsi.php @@ -19,8 +19,11 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Module; +use Fisharebest\ExtCalendar\ArabicCalendar; +use Fisharebest\ExtCalendar\CalendarInterface; use Fisharebest\Localization\Locale\LocaleFa; use Fisharebest\Localization\Locale\LocaleInterface; +use Illuminate\Database\Query\Builder; /** * Class LanguageFarsi. @@ -30,6 +33,38 @@ class LanguageFarsi extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['ا', 'ب', 'ت', 'ث', 'ج', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز', 'س', 'ش', 'ص', 'ض', 'ط', 'ظ', 'ع', 'غ', 'ف', 'ق', 'ك', 'ل', 'م', 'ن', 'ه', 'و', 'ي', 'آ', 'ة', 'ى', 'ی']; + } + + /** + * Default calendar used by this language. + * + * @return CalendarInterface + */ + public function calendar(): CalendarInterface + { + return new ArabicCalendar(); + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_persian_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguageFinnish.php b/app/Module/LanguageFinnish.php index aa862202b9..4156a38059 100644 --- a/app/Module/LanguageFinnish.php +++ b/app/Module/LanguageFinnish.php @@ -30,6 +30,16 @@ class LanguageFinnish extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'Å', 'Ä', 'Ö']; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageGerman.php b/app/Module/LanguageGerman.php index 52ce4f6b95..4a0849ea4b 100644 --- a/app/Module/LanguageGerman.php +++ b/app/Module/LanguageGerman.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleDe; use Fisharebest\Localization\Locale\LocaleInterface; +use Illuminate\Database\Query\Builder; /** * Class LanguageGerman. @@ -30,6 +31,28 @@ class LanguageGerman extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Some languages treat certain letter-combinations as equivalent. + * + * @return array<string,string> + */ + public function equivalentLetters(): array + { + return ['ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'ẞ' => 'ss', 'Ä' => 'AE', 'Ö' => 'OE', 'Ü' => 'UE', 'ß' => 'SS']; + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_german2_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageGreek.php b/app/Module/LanguageGreek.php index 66564d4f2d..c613087607 100644 --- a/app/Module/LanguageGreek.php +++ b/app/Module/LanguageGreek.php @@ -30,6 +30,16 @@ class LanguageGreek extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['Α', 'Β', 'Γ', 'Δ', 'Ε', 'Ζ', 'Η', 'Θ', 'Ι', 'Κ', 'Λ', 'Μ', 'Ν', 'Ξ', 'Ο', 'Π', 'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω']; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageHebrew.php b/app/Module/LanguageHebrew.php index 45218848a1..7ef112bc98 100644 --- a/app/Module/LanguageHebrew.php +++ b/app/Module/LanguageHebrew.php @@ -19,6 +19,8 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Module; +use Fisharebest\ExtCalendar\JewishCalendar; +use Fisharebest\ExtCalendar\CalendarInterface; use Fisharebest\Localization\Locale\LocaleHe; use Fisharebest\Localization\Locale\LocaleInterface; @@ -30,6 +32,26 @@ class LanguageHebrew extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ', 'ק', 'ר', 'ש', 'ת']; + } + + /** + * Default calendar used by this language. + * + * @return CalendarInterface + */ + public function calendar(): CalendarInterface + { + return new JewishCalendar(); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageHungarian.php b/app/Module/LanguageHungarian.php index 0bc1fd063e..81776fcd7c 100644 --- a/app/Module/LanguageHungarian.php +++ b/app/Module/LanguageHungarian.php @@ -21,6 +21,10 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleHu; use Fisharebest\Localization\Locale\LocaleInterface; +use Illuminate\Database\Query\Builder; + +use function mb_substr; +use function str_starts_with; /** * Class LanguageHungarian. @@ -30,6 +34,56 @@ class LanguageHungarian extends AbstractModule implements ModuleLanguageInterfac use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['A', 'Á', 'B', 'C', 'CS', 'D', 'DZ', 'DZS', 'E', 'É', 'F', 'G', 'GY', 'H', 'I', 'Í', 'J', 'K', 'L', 'LY', 'M', 'N', 'NY', 'O', 'Ó', 'Ö', 'Ő', 'P', 'Q', 'R', 'S', 'SZ', 'T', 'TY', 'U', 'Ú', 'Ü', 'Ű', 'V', 'W', 'X', 'Y', 'Z', 'ZS']; + } + + /** + * One of: 'DMY', 'MDY', 'YMD'. + * + * @return string + */ + public function dateOrder(): string + { + return 'YMD'; + } + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string + { + foreach (['DZS', 'DZ', 'GY', 'LY', 'NY', 'SZ', 'TY', 'ZS'] as $digraph) { + if (str_starts_with($string, $digraph)) { + return $digraph; + } + } + + return mb_substr($string, 0, 1); + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_hungarian_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageIcelandic.php b/app/Module/LanguageIcelandic.php index 953c3acb02..d92bd561b6 100644 --- a/app/Module/LanguageIcelandic.php +++ b/app/Module/LanguageIcelandic.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleIs; +use Illuminate\Database\Query\Builder; /** * Class LanguageIcelandic. @@ -30,6 +31,18 @@ class LanguageIcelandic extends AbstractModule implements ModuleLanguageInterfac use ModuleLanguageTrait; /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_icelandic_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageKazhak.php b/app/Module/LanguageKazhak.php index 1e8b020b8c..72e49d0cef 100644 --- a/app/Module/LanguageKazhak.php +++ b/app/Module/LanguageKazhak.php @@ -30,6 +30,16 @@ class LanguageKazhak extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я']; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageLatvian.php b/app/Module/LanguageLatvian.php index d6b7beee70..65c7000f0f 100644 --- a/app/Module/LanguageLatvian.php +++ b/app/Module/LanguageLatvian.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleLv; +use Illuminate\Database\Query\Builder; /** * Class LanguageLatvian. @@ -40,6 +41,18 @@ class LanguageLatvian extends AbstractModule implements ModuleLanguageInterface } /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_latvian_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageLithuanian.php b/app/Module/LanguageLithuanian.php index 9469fee744..f0cf687464 100644 --- a/app/Module/LanguageLithuanian.php +++ b/app/Module/LanguageLithuanian.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleLt; +use Illuminate\Database\Query\Builder; /** * Class LanguageLithuanian. @@ -30,6 +31,38 @@ class LanguageLithuanian extends AbstractModule implements ModuleLanguageInterfa use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['A', 'Ą', 'B', 'C', 'Č', 'D', 'E', 'Ę', 'Ė', 'F', 'G', 'H', 'I', 'Y', 'Į', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'Š', 'T', 'U', 'Ų', 'Ū', 'V', 'Z', 'Ž']; + } + + /** + * One of: 'DMY', 'MDY', 'YMD'. + * + * @return string + */ + public function dateOrder(): string + { + return 'YMD'; + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_lithuanian_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageNorwegianBokmal.php b/app/Module/LanguageNorwegianBokmal.php index ca0f00e065..4a100593d8 100644 --- a/app/Module/LanguageNorwegianBokmal.php +++ b/app/Module/LanguageNorwegianBokmal.php @@ -22,6 +22,9 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleNb; +use function mb_substr; +use function str_starts_with; + /** * Class LanguageNorwegianBokmal. */ @@ -30,6 +33,42 @@ class LanguageNorwegianBokmal extends AbstractModule implements ModuleLanguageIn use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'Æ', 'Ø', 'Å']; + } + + /** + * Some languages treat certain letter-combinations as equivalent. + * + * @return array<string,string> + */ + public function equivalentLetters(): array + { + return ['aa' => 'å', 'aA' => 'å', 'Aa' => 'Å', 'AA' => 'Å']; + } + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string + { + if (str_starts_with($string, 'AA')) { + return 'Å'; + } + + return mb_substr($string, 0, 1); + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguageNorwegianNynorsk.php b/app/Module/LanguageNorwegianNynorsk.php index 42ac16f294..96c8ff7243 100644 --- a/app/Module/LanguageNorwegianNynorsk.php +++ b/app/Module/LanguageNorwegianNynorsk.php @@ -22,6 +22,8 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleNn; +use function mb_substr; + /** * Class LanguageNorwegianNynorsk. */ @@ -30,6 +32,42 @@ class LanguageNorwegianNynorsk extends AbstractModule implements ModuleLanguageI use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'Æ', 'Ø', 'Å']; + } + + /** + * Some languages treat certain letter-combinations as equivalent. + * + * @return array<string,string> + */ + public function equivalentLetters(): array + { + return ['aa' => 'å', 'aA' => 'å', 'Aa' => 'Å', 'AA' => 'Å']; + } + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string + { + if (str_starts_with($string, 'AA')) { + return 'Å'; + } + + return mb_substr($string, 0, 1); + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguagePolish.php b/app/Module/LanguagePolish.php index 29db5a75b5..d0e622e3d4 100644 --- a/app/Module/LanguagePolish.php +++ b/app/Module/LanguagePolish.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocalePl; +use Illuminate\Database\Query\Builder; /** * Class LanguagePolish. @@ -30,6 +31,28 @@ class LanguagePolish extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'Ź', 'Ż']; + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_polish_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageRomanian.php b/app/Module/LanguageRomanian.php index 0629ffadb2..b56aa9b32d 100644 --- a/app/Module/LanguageRomanian.php +++ b/app/Module/LanguageRomanian.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleRo; +use Illuminate\Database\Query\Builder; /** * Class LanguageRomanian. @@ -30,6 +31,28 @@ class LanguageRomanian extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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']; + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_romanian_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguageRussian.php b/app/Module/LanguageRussian.php index 66e9b7e784..f4a4335b69 100644 --- a/app/Module/LanguageRussian.php +++ b/app/Module/LanguageRussian.php @@ -30,6 +30,16 @@ class LanguageRussian extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я']; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageSerbian.php b/app/Module/LanguageSerbian.php index de963cf589..205a676f5b 100644 --- a/app/Module/LanguageSerbian.php +++ b/app/Module/LanguageSerbian.php @@ -30,6 +30,16 @@ class LanguageSerbian extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я']; + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguageSerbianLatin.php b/app/Module/LanguageSerbianLatin.php index c2a661fa90..16c573945a 100644 --- a/app/Module/LanguageSerbianLatin.php +++ b/app/Module/LanguageSerbianLatin.php @@ -30,6 +30,16 @@ class LanguageSerbianLatin extends AbstractModule implements ModuleLanguageInter use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'Ž']; + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguageSlovakian.php b/app/Module/LanguageSlovakian.php index d0d1bbafb9..117ed35ff3 100644 --- a/app/Module/LanguageSlovakian.php +++ b/app/Module/LanguageSlovakian.php @@ -23,7 +23,9 @@ use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleSk; use Fisharebest\Webtrees\Relationship; +use function mb_substr; use function str_repeat; +use function str_starts_with; /** * Class LanguageSlovakian. @@ -75,6 +77,34 @@ class LanguageSlovakian extends AbstractModule implements ModuleLanguageInterfac ]; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['A', 'Á', 'Ä', 'B', 'C', 'Č', 'D', 'Ď', 'DZ', 'DŽ', 'E', 'É', 'F', 'G', 'H', 'CH', 'I', 'Í', 'J', 'K', 'L', 'Ľ', 'Ĺ', 'M', 'N', 'Ň', 'O', 'Ó', 'Ô', 'P', 'Q', 'R', 'Ŕ', 'S', 'Š', 'T', 'Ť', 'U', 'Ú', 'V', 'W', 'X', 'Y', 'Ý', 'Z', 'Ž']; + } + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string + { + foreach (['CH', 'DZ', 'DŽ'] as $digraph) { + if (str_starts_with($string, $digraph)) { + return $digraph; + } + } + + return mb_substr($string, 0, 1); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageSlovenian.php b/app/Module/LanguageSlovenian.php index 60d4023e08..5f48a98773 100644 --- a/app/Module/LanguageSlovenian.php +++ b/app/Module/LanguageSlovenian.php @@ -30,6 +30,16 @@ class LanguageSlovenian extends AbstractModule implements ModuleLanguageInterfac use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'Ž']; + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguageSpanish.php b/app/Module/LanguageSpanish.php index 016c3b4320..131cabc03c 100644 --- a/app/Module/LanguageSpanish.php +++ b/app/Module/LanguageSpanish.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleEs; use Fisharebest\Localization\Locale\LocaleInterface; +use Illuminate\Database\Query\Builder; /** * Class LanguageSpanish. @@ -30,6 +31,28 @@ class LanguageSpanish extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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']; + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_spanish2_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageSwedish.php b/app/Module/LanguageSwedish.php index f7aa9d78cb..68140fbd42 100644 --- a/app/Module/LanguageSwedish.php +++ b/app/Module/LanguageSwedish.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleSv; +use Illuminate\Database\Query\Builder; /** * Class LanguageSwedish. @@ -30,6 +31,28 @@ class LanguageSwedish extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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', 'Å', 'Ä', 'Ö']; + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_swedish_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageTatar.php b/app/Module/LanguageTatar.php index 1415abaac5..b3a9861fab 100644 --- a/app/Module/LanguageTatar.php +++ b/app/Module/LanguageTatar.php @@ -30,6 +30,16 @@ class LanguageTatar extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я']; + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguageTurkish.php b/app/Module/LanguageTurkish.php index 04a0987264..245ec0da56 100644 --- a/app/Module/LanguageTurkish.php +++ b/app/Module/LanguageTurkish.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleTr; +use Illuminate\Database\Query\Builder; /** * Class LanguageTurkish. @@ -30,6 +31,28 @@ class LanguageTurkish extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['A', 'B', 'C', 'Ç', 'D', 'E', 'F', 'G', 'Ğ', 'H', 'I', 'İ', 'J', 'K', 'L', 'M', 'N', 'O', 'Ö', 'P', 'R', 'S', 'Ş', 'T', 'U', 'Ü', 'V', 'Y', 'Z']; + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_turkish_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageUkranian.php b/app/Module/LanguageUkranian.php index 38d2a10fa0..57874a8522 100644 --- a/app/Module/LanguageUkranian.php +++ b/app/Module/LanguageUkranian.php @@ -30,6 +30,16 @@ class LanguageUkranian extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я']; + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageUrdu.php b/app/Module/LanguageUrdu.php index c11274b2b3..7c5b88caf8 100644 --- a/app/Module/LanguageUrdu.php +++ b/app/Module/LanguageUrdu.php @@ -19,6 +19,8 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Module; +use Fisharebest\ExtCalendar\ArabicCalendar; +use Fisharebest\ExtCalendar\CalendarInterface; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleUr; @@ -30,6 +32,26 @@ class LanguageUrdu extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['ا', 'ب', 'ت', 'ث', 'ج', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز', 'س', 'ش', 'ص', 'ض', 'ط', 'ظ', 'ع', 'غ', 'ف', 'ق', 'ك', 'ل', 'م', 'ن', 'ه', 'و', 'ي', 'آ', 'ة', 'ى', 'ی']; + } + + /** + * Default calendar used by this language. + * + * @return CalendarInterface + */ + public function calendar(): CalendarInterface + { + return new ArabicCalendar(); + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/LanguageVietnamese.php b/app/Module/LanguageVietnamese.php index f728aad535..b4b2e1d17a 100644 --- a/app/Module/LanguageVietnamese.php +++ b/app/Module/LanguageVietnamese.php @@ -21,6 +21,7 @@ namespace Fisharebest\Webtrees\Module; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleVi; +use Illuminate\Database\Query\Builder; /** * Class LanguageVietnamese. @@ -30,6 +31,18 @@ class LanguageVietnamese extends AbstractModule implements ModuleLanguageInterfa use ModuleLanguageTrait; /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column . ' /*! COLLATE utf8_vietnamese_ci */', 'LIKE', '\\' . $letter . '%'); + } + + /** * @return LocaleInterface */ public function locale(): LocaleInterface diff --git a/app/Module/LanguageYiddish.php b/app/Module/LanguageYiddish.php index 9aa12d654a..a6747002c2 100644 --- a/app/Module/LanguageYiddish.php +++ b/app/Module/LanguageYiddish.php @@ -19,6 +19,8 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Module; +use Fisharebest\ExtCalendar\CalendarInterface; +use Fisharebest\ExtCalendar\JewishCalendar; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Localization\Locale\LocaleYi; @@ -30,6 +32,26 @@ class LanguageYiddish extends AbstractModule implements ModuleLanguageInterface use ModuleLanguageTrait; /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ז', 'ח', 'ט', 'י', 'כ', 'ל', 'מ', 'נ', 'ס', 'ע', 'פ', 'צ', 'ק', 'ר', 'ש', 'ת']; + } + + /** + * Default calendar used by this language. + * + * @return CalendarInterface + */ + public function calendar(): CalendarInterface + { + return new JewishCalendar(); + } + + /** * Should this module be enabled when it is first installed? * * @return bool diff --git a/app/Module/ModuleLanguageInterface.php b/app/Module/ModuleLanguageInterface.php index a7707d6a64..9dce0f9b7a 100644 --- a/app/Module/ModuleLanguageInterface.php +++ b/app/Module/ModuleLanguageInterface.php @@ -19,8 +19,10 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Module; +use Fisharebest\ExtCalendar\CalendarInterface; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Webtrees\Relationship; +use Illuminate\Database\Query\Builder; /** * Interface ModuleLanguageInterface - provide translation and localization. @@ -28,6 +30,53 @@ use Fisharebest\Webtrees\Relationship; interface ModuleLanguageInterface extends ModuleInterface { /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array; + + /** + * Default calendar used by this language. + * + * @return CalendarInterface + */ + public function calendar(): CalendarInterface; + + /** + * One of: 'DMY', 'MDY', 'YMD'. + * + * @return string + */ + public function dateOrder(): string; + + /** + * Some languages treat certain letter-combinations as equivalent. + * + * @return array<string,string> + */ + public function equivalentLetters(): array; + + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string; + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void; + + /** * @return LocaleInterface */ public function locale(): LocaleInterface; diff --git a/app/Module/ModuleLanguageTrait.php b/app/Module/ModuleLanguageTrait.php index 48078441fc..a15331cefc 100644 --- a/app/Module/ModuleLanguageTrait.php +++ b/app/Module/ModuleLanguageTrait.php @@ -19,10 +19,15 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Module; +use Fisharebest\ExtCalendar\CalendarInterface; +use Fisharebest\ExtCalendar\GregorianCalendar; use Fisharebest\Localization\Locale\LocaleEnUs; use Fisharebest\Localization\Locale\LocaleInterface; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Relationship; +use Illuminate\Database\Query\Builder; + +use function mb_substr; /** * Trait ModuleLanguageEventsTrait - default implementation of ModuleLanguageInterface. @@ -30,6 +35,70 @@ use Fisharebest\Webtrees\Relationship; trait ModuleLanguageTrait { /** + * Phone-book ordering of letters. + * + * @return array<int,string> + */ + public function alphabet(): array + { + return ['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']; + } + + /** + * Default calendar used by this language. + * + * @return CalendarInterface + */ + public function calendar(): CalendarInterface + { + return new GregorianCalendar(); + } + + /** + * One of: 'DMY', 'MDY', 'YMD'. + * + * @return string + */ + public function dateOrder(): string + { + return 'DMY'; + } + + /** + * Some languages treat certain letter-combinations as equivalent. + * + * @return array<string,string> + */ + public function equivalentLetters(): array + { + return []; + } + + /** + * Some languages use digraphs and trigraphs. + * + * @param string $string + * + * @return string + */ + public function initialLetter(string $string): string + { + return mb_substr($string, 0, 1); + } + + /** + * @param string $column + * @param string $letter + * @param Builder $query + * + * @return void + */ + public function initialLetterSQL(string $column, string $letter, Builder $query): void + { + $query->where($column, 'LIKE', '\\' . $letter . '%'); + } + + /** * How should this module be identified in the control panel, etc.? * * @return string diff --git a/app/Module/TopSurnamesModule.php b/app/Module/TopSurnamesModule.php index 259c6bbaaa..47bcb2c63e 100644 --- a/app/Module/TopSurnamesModule.php +++ b/app/Module/TopSurnamesModule.php @@ -116,7 +116,7 @@ class TopSurnamesModule extends AbstractModule implements ModuleBlockInterface $variants = DB::table('name') ->where('n_file', '=', $tree->id()) ->where(new Expression('n_surn /*! COLLATE utf8_bin */'), '=', $top_surname) - ->groupBy(['surname']) + ->groupBy([new Expression('n_surname /*! COLLATE utf8_bin */')]) ->select([new Expression('n_surname /*! COLLATE utf8_bin */ AS surname'), new Expression('count(*) AS total')]) ->pluck('total', 'surname') ->map(static fn (string $n): int => (int) $n) @@ -168,6 +168,7 @@ class TopSurnamesModule extends AbstractModule implements ModuleBlockInterface case 'table': default: + uksort($all_surnames, I18N::comparator()); $content = view('lists/surnames-table', [ 'families' => false, 'module' => $module, diff --git a/app/Services/LocalizationService.php b/app/Services/LocalizationService.php index 2808ce71e5..b988c9475f 100644 --- a/app/Services/LocalizationService.php +++ b/app/Services/LocalizationService.php @@ -32,6 +32,8 @@ use function substr_compare; /** * Utilities to support localization. + * + * @deprecated - Will be removed in webtrees 2.2 - Use I18N::language() instead */ class LocalizationService { diff --git a/tests/TestCase.php b/tests/TestCase.php index bea3e787b3..2a9b8f39fd 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -91,8 +91,6 @@ class TestCase extends \PHPUnit\Framework\TestCase (new WebRoutes())->load($router_container->getMap()); Webtrees::set(RouterContainer::class, $router_container); - I18N::init('en-US', true); - if (static::$uses_database) { static::createTestDatabase(); @@ -101,6 +99,10 @@ class TestCase extends \PHPUnit\Framework\TestCase // Boot modules (new ModuleService())->bootModules(new WebtreesTheme()); + + I18N::init('en-US'); + } else { + I18N::init('en-US', true); } } diff --git a/tests/app/Services/LocalizationServiceTest.php b/tests/app/Services/LocalizationServiceTest.php deleted file mode 100644 index 8198aef47e..0000000000 --- a/tests/app/Services/LocalizationServiceTest.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php - -/** - * webtrees: online genealogy - * Copyright (C) 2022 webtrees development team - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -declare(strict_types=1); - -namespace Fisharebest\Webtrees\Services; - -use Fisharebest\Webtrees\TestCase; - -/** - * Test harness for the class LocalizationService - */ -class LocalizationServiceTest extends TestCase -{ - /** - * @covers \Fisharebest\Webtrees\Services\LocalizationService::dateFormatToOrder - * - * @return void - */ - public function testDateFormatToOrder(): void - { - $localization_service = new LocalizationService(); - - // Chinese - self::assertSame('YMD', $localization_service->dateFormatToOrder('%Y年 %n月 %j日')); - - // American - self::assertSame('MDY', $localization_service->dateFormatToOrder('%F %j, %Y')); - - // European - self::assertSame('DMY', $localization_service->dateFormatToOrder('%j %F %Y')); - } -} diff --git a/tests/feature/IndividualListTest.php b/tests/feature/IndividualListTest.php index 65f95ba055..20477b1f8f 100644 --- a/tests/feature/IndividualListTest.php +++ b/tests/feature/IndividualListTest.php @@ -22,7 +22,6 @@ namespace Fisharebest\Webtrees; use Fig\Http\Message\RequestMethodInterface; use Fig\Http\Message\StatusCodeInterface; use Fisharebest\Webtrees\Module\IndividualListModule; -use Fisharebest\Webtrees\Services\LocalizationService; /** * Test the individual lists. @@ -40,7 +39,7 @@ class IndividualListTest extends TestCase public function testIndividualList(): void { $tree = $this->importTree('demo.ged'); - $list_module = new IndividualListModule(new LocalizationService()); + $list_module = new IndividualListModule(); $request = self::createRequest(RequestMethodInterface::METHOD_GET, [], [], [], ['tree' => $tree]); $response = $list_module->handle($request); |
