1<?php 2 3/** 4 * webtrees: online genealogy 5 * Copyright (C) 2022 webtrees development team 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 */ 17 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Services; 21 22use Fisharebest\Webtrees\Auth; 23use Fisharebest\Webtrees\Fact; 24use Fisharebest\Webtrees\Family; 25use Fisharebest\Webtrees\I18N; 26use Fisharebest\Webtrees\Individual; 27use Fisharebest\Webtrees\Module\ModuleLanguageInterface; 28use Fisharebest\Webtrees\Relationship; 29 30use function abs; 31use function array_key_exists; 32use function array_merge; 33use function array_reduce; 34use function array_slice; 35use function count; 36use function implode; 37use function intdiv; 38use function min; 39use function preg_match; 40use function sprintf; 41use function strlen; 42use function substr; 43 44/** 45 * Names for relationships. 46 */ 47class RelationshipService 48{ 49 private const COMPONENTS = [ 50 'CHIL' => [ 51 'CHIL' => Relationship::SIBLINGS, 52 'HUSB' => Relationship::PARENTS, 53 'WIFE' => Relationship::PARENTS, 54 ], 55 'HUSB' => [ 56 'CHIL' => Relationship::CHILDREN, 57 'HUSB' => Relationship::SPOUSES, 58 'WIFE' => Relationship::SPOUSES, 59 ], 60 'WIFE' => [ 61 'CHIL' => Relationship::CHILDREN, 62 'HUSB' => Relationship::SPOUSES, 63 'WIFE' => Relationship::SPOUSES, 64 ], 65 ]; 66 67 /** 68 * For close family relationships, such as the families tab, associates, and the family navigator. 69 * 70 * @param Individual $individual1 71 * @param Individual $individual2 72 * 73 * @return string 74 */ 75 public function getCloseRelationshipName(Individual $individual1, Individual $individual2): string 76 { 77 $language = app(ModuleService::class) 78 ->findByInterface(ModuleLanguageInterface::class, true) 79 ->first(fn (ModuleLanguageInterface $language): bool => $language->locale()->languageTag() === I18N::languageTag()); 80 81 $path = $this->getCloseRelationship($individual1, $individual2); 82 83 // No relationship found? 84 if ($path === []) { 85 return ''; 86 } 87 88 return $this->nameFromPath($path, $language); 89 } 90 91 /** 92 * Get relationship between two individuals in the gedcom. This function 93 * takes account of pending changes, so we can display names of newly added 94 * relations. 95 * 96 * @param Individual $individual1 97 * @param Individual $individual2 98 * @param int $maxlength 99 * 100 * @return array<Individual|Family> An array of nodes on the relationship path 101 */ 102 private function getCloseRelationship(Individual $individual1, Individual $individual2, int $maxlength = 4): array 103 { 104 if ($individual1 === $individual2) { 105 return [$individual1]; 106 } 107 108 // Only examine each individual once 109 $visited = [ 110 $individual1->xref() => true, 111 ]; 112 113 // Build paths out from the first individual 114 $paths = [ 115 [$individual1], 116 ]; 117 118 // Loop over paths of length 1, 2, 3, ... 119 while ($maxlength >= 0) { 120 $maxlength--; 121 122 foreach ($paths as $i => $path) { 123 // Try each new relation from the end of the path 124 $indi = $path[count($path) - 1]; 125 126 // Parents and siblings 127 foreach ($indi->childFamilies(Auth::PRIV_HIDE) as $family) { 128 $visited[$family->xref()] = true; 129 foreach ($family->spouses(Auth::PRIV_HIDE) as $spouse) { 130 if (!isset($visited[$spouse->xref()])) { 131 $new_path = $path; 132 $new_path[] = $family; 133 $new_path[] = $spouse; 134 if ($spouse === $individual2) { 135 return $new_path; 136 } 137 138 $paths[] = $new_path; 139 $visited[$spouse->xref()] = true; 140 } 141 } 142 foreach ($family->children(Auth::PRIV_HIDE) as $child) { 143 if (!isset($visited[$child->xref()])) { 144 $new_path = $path; 145 $new_path[] = $family; 146 $new_path[] = $child; 147 if ($child === $individual2) { 148 return $new_path; 149 } 150 151 $paths[] = $new_path; 152 $visited[$child->xref()] = true; 153 } 154 } 155 } 156 157 // Spouses and children 158 foreach ($indi->spouseFamilies(Auth::PRIV_HIDE) as $family) { 159 $visited[$family->xref()] = true; 160 foreach ($family->spouses(Auth::PRIV_HIDE) as $spouse) { 161 if (!isset($visited[$spouse->xref()])) { 162 $new_path = $path; 163 $new_path[] = $family; 164 $new_path[] = $spouse; 165 if ($spouse === $individual2) { 166 return $new_path; 167 } 168 169 $paths[] = $new_path; 170 $visited[$spouse->xref()] = true; 171 } 172 } 173 foreach ($family->children(Auth::PRIV_HIDE) as $child) { 174 if (!isset($visited[$child->xref()])) { 175 $new_path = $path; 176 $new_path[] = $family; 177 $new_path[] = $child; 178 if ($child === $individual2) { 179 return $new_path; 180 } 181 182 $paths[] = $new_path; 183 $visited[$child->xref()] = true; 184 } 185 } 186 } 187 unset($paths[$i]); 188 } 189 } 190 191 return []; 192 } 193 194 /** 195 * @param array<Individual|Family> $nodes 196 * @param ModuleLanguageInterface $language 197 * 198 * @return string 199 */ 200 public function nameFromPath(array $nodes, ModuleLanguageInterface $language): string 201 { 202 // The relationship matching algorithm could be used for this, but it is more efficient to check it here. 203 if (count($nodes) === 1) { 204 return $this->reflexivePronoun($nodes[0]); 205 } 206 207 // The relationship definitions for the language. 208 $relationships = $language->relationships(); 209 210 // We don't strictly need this, as all the information is contained in the nodes. 211 // But it gives us simpler code and better performance. 212 // It is also needed for the legacy algorithm. 213 $pattern = $this->components($nodes); 214 215 // No definitions for this language? Use the legacy algorithm. 216 if ($relationships === []) { 217 return $this->legacyNameAlgorithm(implode('', $pattern), $nodes[0], $nodes[count($nodes) - 1]); 218 } 219 220 // Match the relationship, using a longest-substring algorithm. 221 $relationships = $this->matchRelationships($nodes, $pattern, $relationships); 222 223 // Reduce the genitive-nominative chain to a single string. 224 return array_reduce($relationships, static function (array $carry, array $item): array { 225 return [sprintf($carry[1], $item[0]), sprintf($carry[1], $item[1])]; 226 }, [0 => '', 1 => '%s'])[0]; 227 } 228 229 /** 230 * Generate a reflexive pronoun for an individual 231 * 232 * @param Individual $individual 233 * 234 * @return string 235 */ 236 protected function reflexivePronoun(Individual $individual): string 237 { 238 switch ($individual->sex()) { 239 case 'M': 240 /* I18N: reflexive pronoun */ 241 return I18N::translate('himself'); 242 case 'F': 243 /* I18N: reflexive pronoun */ 244 return I18N::translate('herself'); 245 default: 246 /* I18N: reflexive pronoun - gender neutral version of himself/herself */ 247 return I18N::translate('themself'); 248 } 249 } 250 251 /** 252 * Convert a relationship path into its component pieces; brother, wife, mother, daughter, etc. 253 * 254 * @param array<Individual|Family> $nodes - Alternating list of Individual and Family objects 255 * 256 * @return array<string> 257 */ 258 private function components(array $nodes): array 259 { 260 $pattern = []; 261 262 $count = count($nodes); 263 264 for ($i = 1; $i < $count; $i += 2) { 265 $prev = $nodes[$i - 1]; 266 $family = $nodes[$i]; 267 $next = $nodes[$i + 1]; 268 269 preg_match('/\n1 (HUSB|WIFE|CHIL) @' . $prev->xref() . '@/', $family->gedcom(), $match); 270 $rel1 = $match[1] ?? 'xxx'; 271 272 preg_match('/\n1 (HUSB|WIFE|CHIL) @' . $next->xref() . '@/', $family->gedcom(), $match); 273 $rel2 = $match[1] ?? 'xxx'; 274 275 $pattern[] = self::COMPONENTS[$rel1][$rel2][$next->sex()] ?? 'xxx'; 276 } 277 278 return $pattern; 279 } 280 281 /** 282 * @param array<Individual|Family> $nodes 283 * @param array<string> $pattern 284 * @param array<Relationship> $relationships 285 * 286 * @return array<Relationship> 287 */ 288 protected function matchRelationships(array $nodes, array $pattern, array $relationships): array 289 { 290 $count = count($pattern); 291 292 // Look for the longest matchable series of components 293 for ($length = $count; $length > 0; $length--) { 294 for ($start = $count - $length; $start >= 0; $start--) { 295 foreach ($relationships as $relationship) { 296 $path_slice = array_slice($nodes, $start * 2, $length * 2 + 1); 297 $pattern_slice = array_slice($pattern, $start, $length); 298 $result = $relationship->match($path_slice, $pattern_slice); 299 300 if ($result !== null) { 301 $nodes_before = array_slice($nodes, 0, $start * 2 + 1); 302 $pattern_before = array_slice($pattern, 0, $start); 303 $result_before = $this->matchRelationships($nodes_before, $pattern_before, $relationships); 304 305 $nodes_after = array_slice($nodes, ($start + $length) * 2); 306 $pattern_after = array_slice($pattern, $start + $length); 307 $result_after = $this->matchRelationships($nodes_after, $pattern_after, $relationships); 308 309 return array_merge($result_before, [$result], $result_after); 310 } 311 } 312 } 313 } 314 315 return []; 316 } 317 318 /** 319 * @param string $path 320 * @param Individual|null $person1 321 * @param Individual|null $person2 322 * 323 * @return string 324 * 325 * @deprecated This code was originally Functions::getRelationshipNameFromPath 326 */ 327 public function legacyNameAlgorithm(string $path, Individual $person1 = null, Individual $person2 = null): string 328 { 329 // The path does not include the starting person. In some languages, the 330 // translation for a man’s (relative) is different from a woman’s (relative), 331 // due to inflection. 332 $sex1 = $person1 ? $person1->sex() : 'U'; 333 334 // The sex of the last person in the relationship determines the name in 335 // many cases. e.g. great-aunt / great-uncle 336 if (preg_match('/(fat|hus|son|bro)$/', $path)) { 337 $sex2 = 'M'; 338 } elseif (preg_match('/(mot|wif|dau|sis)$/', $path)) { 339 $sex2 = 'F'; 340 } else { 341 $sex2 = 'U'; 342 } 343 344 switch ($path) { 345 case '': 346 return I18N::translate('self'); 347 // Level One relationships 348 case 'mot': 349 return I18N::translate('mother'); 350 case 'fat': 351 return I18N::translate('father'); 352 case 'par': 353 return I18N::translate('parent'); 354 case 'hus': 355 if ($person1 instanceof Individual && $person2 instanceof Individual) { 356 // We had the linking family earlier, but lost it. Find it again. 357 foreach ($person1->spouseFamilies(Auth::PRIV_HIDE) as $family) { 358 if ($person2 === $family->spouse($person1)) { 359 $event = $family->facts(['ANUL', 'DIV', 'ENGA', 'MARR'], true, Auth::PRIV_HIDE, true)->last(); 360 361 if ($event instanceof Fact) { 362 switch ($event->tag()) { 363 case 'FAM:ANUL': 364 case 'FAM:DIV': 365 return I18N::translate('ex-husband'); 366 case 'FAM:MARR': 367 return I18N::translate('husband'); 368 case 'FAM:ENGA': 369 return I18N::translate('fiancé'); 370 } 371 } 372 } 373 } 374 } 375 376 return I18N::translateContext('MALE', 'partner'); 377 378 case 'wif': 379 if ($person1 instanceof Individual && $person2 instanceof Individual) { 380 // We had the linking family earlier, but lost it. Find it again. 381 foreach ($person1->spouseFamilies(Auth::PRIV_HIDE) as $family) { 382 if ($person2 === $family->spouse($person1)) { 383 $event = $family->facts(['ANUL', 'DIV', 'ENGA', 'MARR'], true, Auth::PRIV_HIDE, true)->last(); 384 385 if ($event instanceof Fact) { 386 switch ($event->tag()) { 387 case 'FAM:ANUL': 388 case 'FAM:DIV': 389 return I18N::translate('ex-wife'); 390 case 'FAM:MARR': 391 return I18N::translate('wife'); 392 case 'FAM:ENGA': 393 return I18N::translate('fiancée'); 394 } 395 } 396 } 397 } 398 } 399 400 return I18N::translateContext('FEMALE', 'partner'); 401 case 'spo': 402 if ($person1 instanceof Individual && $person2 instanceof Individual) { 403 // We had the linking family earlier, but lost it. Find it again. 404 foreach ($person1->spouseFamilies(Auth::PRIV_HIDE) as $family) { 405 if ($person2 === $family->spouse($person1)) { 406 $event = $family->facts(['ANUL', 'DIV', 'ENGA', 'MARR'], true, Auth::PRIV_HIDE, true)->last(); 407 408 if ($event instanceof Fact) { 409 switch ($event->tag()) { 410 case 'FAM:ANUL': 411 case 'FAM:DIV': 412 return I18N::translate('ex-spouse'); 413 case 'FAM:MARR': 414 return I18N::translate('spouse'); 415 case 'FAM:ENGA': 416 return I18N::translate('fiancé(e)'); 417 } 418 } 419 } 420 } 421 } 422 423 return I18N::translate('partner'); 424 425 case 'son': 426 return I18N::translate('son'); 427 case 'dau': 428 return I18N::translate('daughter'); 429 case 'chi': 430 return I18N::translate('child'); 431 case 'bro': 432 if ($person1 && $person2) { 433 $dob1 = $person1->getBirthDate(); 434 $dob2 = $person2->getBirthDate(); 435 if ($dob1->isOK() && $dob2->isOK()) { 436 if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && $dob1->minimumDate()->day > 0 && $dob2->minimumDate()->day > 0) { 437 // Exclude BEF, AFT, etc. 438 return I18N::translate('twin brother'); 439 } 440 441 if ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) { 442 return I18N::translate('younger brother'); 443 } 444 445 if ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) { 446 return I18N::translate('elder brother'); 447 } 448 } 449 } 450 451 return I18N::translate('brother'); 452 case 'sis': 453 if ($person1 && $person2) { 454 $dob1 = $person1->getBirthDate(); 455 $dob2 = $person2->getBirthDate(); 456 if ($dob1->isOK() && $dob2->isOK()) { 457 if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && $dob1->minimumDate()->day > 0 && $dob2->minimumDate()->day > 0) { 458 // Exclude BEF, AFT, etc. 459 return I18N::translate('twin sister'); 460 } 461 462 if ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) { 463 return I18N::translate('younger sister'); 464 } 465 466 if ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) { 467 return I18N::translate('elder sister'); 468 } 469 } 470 } 471 472 return I18N::translate('sister'); 473 case 'sib': 474 if ($person1 && $person2) { 475 $dob1 = $person1->getBirthDate(); 476 $dob2 = $person2->getBirthDate(); 477 if ($dob1->isOK() && $dob2->isOK()) { 478 if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && $dob1->minimumDate()->day > 0 && $dob2->minimumDate()->day > 0) { 479 // Exclude BEF, AFT, etc. 480 return I18N::translate('twin sibling'); 481 } 482 483 if ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) { 484 return I18N::translate('younger sibling'); 485 } 486 487 if ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) { 488 return I18N::translate('elder sibling'); 489 } 490 } 491 } 492 493 return I18N::translate('sibling'); 494 495 // Level Two relationships 496 case 'brochi': 497 return I18N::translateContext('brother’s child', 'nephew/niece'); 498 case 'brodau': 499 return I18N::translateContext('brother’s daughter', 'niece'); 500 case 'broson': 501 return I18N::translateContext('brother’s son', 'nephew'); 502 case 'browif': 503 return I18N::translateContext('brother’s wife', 'sister-in-law'); 504 case 'chichi': 505 return I18N::translateContext('child’s child', 'grandchild'); 506 case 'chidau': 507 return I18N::translateContext('child’s daughter', 'granddaughter'); 508 case 'chihus': 509 return I18N::translateContext('child’s husband', 'son-in-law'); 510 case 'chison': 511 return I18N::translateContext('child’s son', 'grandson'); 512 case 'chispo': 513 return I18N::translateContext('child’s spouse', 'son/daughter-in-law'); 514 case 'chiwif': 515 return I18N::translateContext('child’s wife', 'daughter-in-law'); 516 case 'dauchi': 517 return I18N::translateContext('daughter’s child', 'grandchild'); 518 case 'daudau': 519 return I18N::translateContext('daughter’s daughter', 'granddaughter'); 520 case 'dauhus': 521 return I18N::translateContext('daughter’s husband', 'son-in-law'); 522 case 'dauson': 523 return I18N::translateContext('daughter’s son', 'grandson'); 524 case 'fatbro': 525 return I18N::translateContext('father’s brother', 'uncle'); 526 case 'fatchi': 527 return I18N::translateContext('father’s child', 'half-sibling'); 528 case 'fatdau': 529 return I18N::translateContext('father’s daughter', 'half-sister'); 530 case 'fatfat': 531 return I18N::translateContext('father’s father', 'paternal grandfather'); 532 case 'fatmot': 533 return I18N::translateContext('father’s mother', 'paternal grandmother'); 534 case 'fatpar': 535 return I18N::translateContext('father’s parent', 'paternal grandparent'); 536 case 'fatsib': 537 return I18N::translateContext('father’s sibling', 'aunt/uncle'); 538 case 'fatsis': 539 return I18N::translateContext('father’s sister', 'aunt'); 540 case 'fatson': 541 return I18N::translateContext('father’s son', 'half-brother'); 542 case 'fatwif': 543 return I18N::translateContext('father’s wife', 'step-mother'); 544 case 'husbro': 545 return I18N::translateContext('husband’s brother', 'brother-in-law'); 546 case 'huschi': 547 return I18N::translateContext('husband’s child', 'step-child'); 548 case 'husdau': 549 return I18N::translateContext('husband’s daughter', 'step-daughter'); 550 case 'husfat': 551 return I18N::translateContext('husband’s father', 'father-in-law'); 552 case 'husmot': 553 return I18N::translateContext('husband’s mother', 'mother-in-law'); 554 case 'hussib': 555 return I18N::translateContext('husband’s sibling', 'brother/sister-in-law'); 556 case 'hussis': 557 return I18N::translateContext('husband’s sister', 'sister-in-law'); 558 case 'husson': 559 return I18N::translateContext('husband’s son', 'step-son'); 560 case 'motbro': 561 return I18N::translateContext('mother’s brother', 'uncle'); 562 case 'motchi': 563 return I18N::translateContext('mother’s child', 'half-sibling'); 564 case 'motdau': 565 return I18N::translateContext('mother’s daughter', 'half-sister'); 566 case 'motfat': 567 return I18N::translateContext('mother’s father', 'maternal grandfather'); 568 case 'mothus': 569 return I18N::translateContext('mother’s husband', 'step-father'); 570 case 'motmot': 571 return I18N::translateContext('mother’s mother', 'maternal grandmother'); 572 case 'motpar': 573 return I18N::translateContext('mother’s parent', 'maternal grandparent'); 574 case 'motsib': 575 return I18N::translateContext('mother’s sibling', 'aunt/uncle'); 576 case 'motsis': 577 return I18N::translateContext('mother’s sister', 'aunt'); 578 case 'motson': 579 return I18N::translateContext('mother’s son', 'half-brother'); 580 case 'parbro': 581 return I18N::translateContext('parent’s brother', 'uncle'); 582 case 'parchi': 583 return I18N::translateContext('parent’s child', 'half-sibling'); 584 case 'pardau': 585 return I18N::translateContext('parent’s daughter', 'half-sister'); 586 case 'parfat': 587 return I18N::translateContext('parent’s father', 'grandfather'); 588 case 'parmot': 589 return I18N::translateContext('parent’s mother', 'grandmother'); 590 case 'parpar': 591 return I18N::translateContext('parent’s parent', 'grandparent'); 592 case 'parsib': 593 return I18N::translateContext('parent’s sibling', 'aunt/uncle'); 594 case 'parsis': 595 return I18N::translateContext('parent’s sister', 'aunt'); 596 case 'parson': 597 return I18N::translateContext('parent’s son', 'half-brother'); 598 case 'parspo': 599 return I18N::translateContext('parent’s spouse', 'step-parent'); 600 case 'sibchi': 601 return I18N::translateContext('sibling’s child', 'nephew/niece'); 602 case 'sibdau': 603 return I18N::translateContext('sibling’s daughter', 'niece'); 604 case 'sibson': 605 return I18N::translateContext('sibling’s son', 'nephew'); 606 case 'sibspo': 607 return I18N::translateContext('sibling’s spouse', 'brother/sister-in-law'); 608 case 'sischi': 609 return I18N::translateContext('sister’s child', 'nephew/niece'); 610 case 'sisdau': 611 return I18N::translateContext('sister’s daughter', 'niece'); 612 case 'sishus': 613 return I18N::translateContext('sister’s husband', 'brother-in-law'); 614 case 'sisson': 615 return I18N::translateContext('sister’s son', 'nephew'); 616 case 'sonchi': 617 return I18N::translateContext('son’s child', 'grandchild'); 618 case 'sondau': 619 return I18N::translateContext('son’s daughter', 'granddaughter'); 620 case 'sonson': 621 return I18N::translateContext('son’s son', 'grandson'); 622 case 'sonwif': 623 return I18N::translateContext('son’s wife', 'daughter-in-law'); 624 case 'spobro': 625 return I18N::translateContext('spouse’s brother', 'brother-in-law'); 626 case 'spochi': 627 return I18N::translateContext('spouse’s child', 'step-child'); 628 case 'spodau': 629 return I18N::translateContext('spouse’s daughter', 'step-daughter'); 630 case 'spofat': 631 return I18N::translateContext('spouse’s father', 'father-in-law'); 632 case 'spomot': 633 return I18N::translateContext('spouse’s mother', 'mother-in-law'); 634 case 'sposis': 635 return I18N::translateContext('spouse’s sister', 'sister-in-law'); 636 case 'sposon': 637 return I18N::translateContext('spouse’s son', 'step-son'); 638 case 'spopar': 639 return I18N::translateContext('spouse’s parent', 'mother/father-in-law'); 640 case 'sposib': 641 return I18N::translateContext('spouse’s sibling', 'brother/sister-in-law'); 642 case 'wifbro': 643 return I18N::translateContext('wife’s brother', 'brother-in-law'); 644 case 'wifchi': 645 return I18N::translateContext('wife’s child', 'step-child'); 646 case 'wifdau': 647 return I18N::translateContext('wife’s daughter', 'step-daughter'); 648 case 'wiffat': 649 return I18N::translateContext('wife’s father', 'father-in-law'); 650 case 'wifmot': 651 return I18N::translateContext('wife’s mother', 'mother-in-law'); 652 case 'wifsib': 653 return I18N::translateContext('wife’s sibling', 'brother/sister-in-law'); 654 case 'wifsis': 655 return I18N::translateContext('wife’s sister', 'sister-in-law'); 656 case 'wifson': 657 return I18N::translateContext('wife’s son', 'step-son'); 658 659 // Level Three relationships 660 case 'brochichi': 661 if ($sex1 === 'M') { 662 return I18N::translateContext('(a man’s) brother’s child’s child', 'great-nephew/niece'); 663 } 664 665 return I18N::translateContext('(a woman’s) brother’s child’s child', 'great-nephew/niece'); 666 case 'brochidau': 667 if ($sex1 === 'M') { 668 return I18N::translateContext('(a man’s) brother’s child’s daughter', 'great-niece'); 669 } 670 671 return I18N::translateContext('(a woman’s) brother’s child’s daughter', 'great-niece'); 672 case 'brochison': 673 if ($sex1 === 'M') { 674 return I18N::translateContext('(a man’s) brother’s child’s son', 'great-nephew'); 675 } 676 677 return I18N::translateContext('(a woman’s) brother’s child’s son', 'great-nephew'); 678 case 'brodauchi': 679 if ($sex1 === 'M') { 680 return I18N::translateContext('(a man’s) brother’s daughter’s child', 'great-nephew/niece'); 681 } 682 683 return I18N::translateContext('(a woman’s) brother’s daughter’s child', 'great-nephew/niece'); 684 case 'brodaudau': 685 if ($sex1 === 'M') { 686 return I18N::translateContext('(a man’s) brother’s daughter’s daughter', 'great-niece'); 687 } 688 689 return I18N::translateContext('(a woman’s) brother’s daughter’s daughter', 'great-niece'); 690 case 'brodauhus': 691 return I18N::translateContext('brother’s daughter’s husband', 'nephew-in-law'); 692 case 'brodauson': 693 if ($sex1 === 'M') { 694 return I18N::translateContext('(a man’s) brother’s daughter’s son', 'great-nephew'); 695 } 696 697 return I18N::translateContext('(a woman’s) brother’s daughter’s son', 'great-nephew'); 698 case 'brosonchi': 699 if ($sex1 === 'M') { 700 return I18N::translateContext('(a man’s) brother’s son’s child', 'great-nephew/niece'); 701 } 702 703 return I18N::translateContext('(a woman’s) brother’s son’s child', 'great-nephew/niece'); 704 case 'brosondau': 705 if ($sex1 === 'M') { 706 return I18N::translateContext('(a man’s) brother’s son’s daughter', 'great-niece'); 707 } 708 709 return I18N::translateContext('(a woman’s) brother’s son’s daughter', 'great-niece'); 710 case 'brosonson': 711 if ($sex1 === 'M') { 712 return I18N::translateContext('(a man’s) brother’s son’s son', 'great-nephew'); 713 } 714 715 return I18N::translateContext('(a woman’s) brother’s son’s son', 'great-nephew'); 716 case 'brosonwif': 717 return I18N::translateContext('brother’s son’s wife', 'niece-in-law'); 718 case 'browifbro': 719 return I18N::translateContext('brother’s wife’s brother', 'brother-in-law'); 720 case 'browifsib': 721 return I18N::translateContext('brother’s wife’s sibling', 'brother/sister-in-law'); 722 case 'browifsis': 723 return I18N::translateContext('brother’s wife’s sister', 'sister-in-law'); 724 case 'chichichi': 725 return I18N::translateContext('child’s child’s child', 'great-grandchild'); 726 case 'chichidau': 727 return I18N::translateContext('child’s child’s daughter', 'great-granddaughter'); 728 case 'chichison': 729 return I18N::translateContext('child’s child’s son', 'great-grandson'); 730 case 'chidauchi': 731 return I18N::translateContext('child’s daughter’s child', 'great-grandchild'); 732 case 'chidaudau': 733 return I18N::translateContext('child’s daughter’s daughter', 'great-granddaughter'); 734 case 'chidauhus': 735 return I18N::translateContext('child’s daughter’s husband', 'granddaughter’s husband'); 736 case 'chidauson': 737 return I18N::translateContext('child’s daughter’s son', 'great-grandson'); 738 case 'chisonchi': 739 return I18N::translateContext('child’s son’s child', 'great-grandchild'); 740 case 'chisondau': 741 return I18N::translateContext('child’s son’s daughter', 'great-granddaughter'); 742 case 'chisonson': 743 return I18N::translateContext('child’s son’s son', 'great-grandson'); 744 case 'chisonwif': 745 return I18N::translateContext('child’s son’s wife', 'grandson’s wife'); 746 case 'dauchichi': 747 return I18N::translateContext('daughter’s child’s child', 'great-grandchild'); 748 case 'dauchidau': 749 return I18N::translateContext('daughter’s child’s daughter', 'great-granddaughter'); 750 case 'dauchison': 751 return I18N::translateContext('daughter’s child’s son', 'great-grandson'); 752 case 'daudauchi': 753 return I18N::translateContext('daughter’s daughter’s child', 'great-grandchild'); 754 case 'daudaudau': 755 return I18N::translateContext('daughter’s daughter’s daughter', 'great-granddaughter'); 756 case 'daudauhus': 757 return I18N::translateContext('daughter’s daughter’s husband', 'granddaughter’s husband'); 758 case 'daudauson': 759 return I18N::translateContext('daughter’s daughter’s son', 'great-grandson'); 760 case 'dauhusfat': 761 return I18N::translateContext('daughter’s husband’s father', 'son-in-law’s father'); 762 case 'dauhusmot': 763 return I18N::translateContext('daughter’s husband’s mother', 'son-in-law’s mother'); 764 case 'dauhuspar': 765 return I18N::translateContext('daughter’s husband’s parent', 'son-in-law’s parent'); 766 case 'dausonchi': 767 return I18N::translateContext('daughter’s son’s child', 'great-grandchild'); 768 case 'dausondau': 769 return I18N::translateContext('daughter’s son’s daughter', 'great-granddaughter'); 770 case 'dausonson': 771 return I18N::translateContext('daughter’s son’s son', 'great-grandson'); 772 case 'dausonwif': 773 return I18N::translateContext('daughter’s son’s wife', 'grandson’s wife'); 774 case 'fatbrochi': 775 return I18N::translateContext('father’s brother’s child', 'first cousin'); 776 case 'fatbrodau': 777 return I18N::translateContext('father’s brother’s daughter', 'first cousin'); 778 case 'fatbroson': 779 return I18N::translateContext('father’s brother’s son', 'first cousin'); 780 case 'fatbrowif': 781 return I18N::translateContext('father’s brother’s wife', 'aunt'); 782 case 'fatfatbro': 783 return I18N::translateContext('father’s father’s brother', 'great-uncle'); 784 case 'fatfatfat': 785 return I18N::translateContext('father’s father’s father', 'great-grandfather'); 786 case 'fatfatmot': 787 return I18N::translateContext('father’s father’s mother', 'great-grandmother'); 788 case 'fatfatpar': 789 return I18N::translateContext('father’s father’s parent', 'great-grandparent'); 790 case 'fatfatsib': 791 return I18N::translateContext('father’s father’s sibling', 'great-aunt/uncle'); 792 case 'fatfatsis': 793 return I18N::translateContext('father’s father’s sister', 'great-aunt'); 794 case 'fatmotbro': 795 return I18N::translateContext('father’s mother’s brother', 'great-uncle'); 796 case 'fatmotfat': 797 return I18N::translateContext('father’s mother’s father', 'great-grandfather'); 798 case 'fatmotmot': 799 return I18N::translateContext('father’s mother’s mother', 'great-grandmother'); 800 case 'fatmotpar': 801 return I18N::translateContext('father’s mother’s parent', 'great-grandparent'); 802 case 'fatmotsib': 803 return I18N::translateContext('father’s mother’s sibling', 'great-aunt/uncle'); 804 case 'fatmotsis': 805 return I18N::translateContext('father’s mother’s sister', 'great-aunt'); 806 case 'fatparbro': 807 return I18N::translateContext('father’s parent’s brother', 'great-uncle'); 808 case 'fatparfat': 809 return I18N::translateContext('father’s parent’s father', 'great-grandfather'); 810 case 'fatparmot': 811 return I18N::translateContext('father’s parent’s mother', 'great-grandmother'); 812 case 'fatparpar': 813 return I18N::translateContext('father’s parent’s parent', 'great-grandparent'); 814 case 'fatparsib': 815 return I18N::translateContext('father’s parent’s sibling', 'great-aunt/uncle'); 816 case 'fatparsis': 817 return I18N::translateContext('father’s parent’s sister', 'great-aunt'); 818 case 'fatsischi': 819 return I18N::translateContext('father’s sister’s child', 'first cousin'); 820 case 'fatsisdau': 821 return I18N::translateContext('father’s sister’s daughter', 'first cousin'); 822 case 'fatsishus': 823 return I18N::translateContext('father’s sister’s husband', 'uncle'); 824 case 'fatsisson': 825 return I18N::translateContext('father’s sister’s son', 'first cousin'); 826 case 'fatwifchi': 827 return I18N::translateContext('father’s wife’s child', 'step-sibling'); 828 case 'fatwifdau': 829 return I18N::translateContext('father’s wife’s daughter', 'step-sister'); 830 case 'fatwifson': 831 return I18N::translateContext('father’s wife’s son', 'step-brother'); 832 case 'husbrowif': 833 return I18N::translateContext('husband’s brother’s wife', 'sister-in-law'); 834 case 'hussishus': 835 return I18N::translateContext('husband’s sister’s husband', 'brother-in-law'); 836 case 'hussibchi': 837 return I18N::translateContext('husband’s sibling’s child', 'nephew/niece'); 838 case 'hussischi': 839 return I18N::translateContext('husband’s sister’s child', 'nephew/niece'); 840 case 'husbrochi': 841 return I18N::translateContext('husband’s brother’s child', 'nephew/niece'); 842 case 'hussibdau': 843 return I18N::translateContext('husband’s sibling’s daughter', 'niece'); 844 case 'hussisdau': 845 return I18N::translateContext('husband’s sister’s daughter', 'niece'); 846 case 'husbrodau': 847 return I18N::translateContext('husband’s brother’s daughter', 'niece'); 848 case 'hussibson': 849 return I18N::translateContext('husband’s sibling’s son', 'nephew'); 850 case 'hussisson': 851 return I18N::translateContext('husband’s sister’s son', 'nephew'); 852 case 'husbroson': 853 return I18N::translateContext('husband’s brother’s son', 'nephew'); 854 case 'motbrochi': 855 return I18N::translateContext('mother’s brother’s child', 'first cousin'); 856 case 'motbrodau': 857 return I18N::translateContext('mother’s brother’s daughter', 'first cousin'); 858 case 'motbroson': 859 return I18N::translateContext('mother’s brother’s son', 'first cousin'); 860 case 'motbrowif': 861 return I18N::translateContext('mother’s brother’s wife', 'aunt'); 862 case 'motfatbro': 863 return I18N::translateContext('mother’s father’s brother', 'great-uncle'); 864 case 'motfatfat': 865 return I18N::translateContext('mother’s father’s father', 'great-grandfather'); 866 case 'motfatmot': 867 return I18N::translateContext('mother’s father’s mother', 'great-grandmother'); 868 case 'motfatpar': 869 return I18N::translateContext('mother’s father’s parent', 'great-grandparent'); 870 case 'motfatsib': 871 return I18N::translateContext('mother’s father’s sibling', 'great-aunt/uncle'); 872 case 'motfatsis': 873 return I18N::translateContext('mother’s father’s sister', 'great-aunt'); 874 case 'mothuschi': 875 return I18N::translateContext('mother’s husband’s child', 'step-sibling'); 876 case 'mothusdau': 877 return I18N::translateContext('mother’s husband’s daughter', 'step-sister'); 878 case 'mothusson': 879 return I18N::translateContext('mother’s husband’s son', 'step-brother'); 880 case 'motmotbro': 881 return I18N::translateContext('mother’s mother’s brother', 'great-uncle'); 882 case 'motmotfat': 883 return I18N::translateContext('mother’s mother’s father', 'great-grandfather'); 884 case 'motmotmot': 885 return I18N::translateContext('mother’s mother’s mother', 'great-grandmother'); 886 case 'motmotpar': 887 return I18N::translateContext('mother’s mother’s parent', 'great-grandparent'); 888 case 'motmotsib': 889 return I18N::translateContext('mother’s mother’s sibling', 'great-aunt/uncle'); 890 case 'motmotsis': 891 return I18N::translateContext('mother’s mother’s sister', 'great-aunt'); 892 case 'motparbro': 893 return I18N::translateContext('mother’s parent’s brother', 'great-uncle'); 894 case 'motparfat': 895 return I18N::translateContext('mother’s parent’s father', 'great-grandfather'); 896 case 'motparmot': 897 return I18N::translateContext('mother’s parent’s mother', 'great-grandmother'); 898 case 'motparpar': 899 return I18N::translateContext('mother’s parent’s parent', 'great-grandparent'); 900 case 'motparsib': 901 return I18N::translateContext('mother’s parent’s sibling', 'great-aunt/uncle'); 902 case 'motparsis': 903 return I18N::translateContext('mother’s parent’s sister', 'great-aunt'); 904 case 'motsischi': 905 return I18N::translateContext('mother’s sister’s child', 'first cousin'); 906 case 'motsisdau': 907 return I18N::translateContext('mother’s sister’s daughter', 'first cousin'); 908 case 'motsishus': 909 return I18N::translateContext('mother’s sister’s husband', 'uncle'); 910 case 'motsisson': 911 return I18N::translateContext('mother’s sister’s son', 'first cousin'); 912 case 'parbrowif': 913 return I18N::translateContext('parent’s brother’s wife', 'aunt'); 914 case 'parfatbro': 915 return I18N::translateContext('parent’s father’s brother', 'great-uncle'); 916 case 'parfatfat': 917 return I18N::translateContext('parent’s father’s father', 'great-grandfather'); 918 case 'parfatmot': 919 return I18N::translateContext('parent’s father’s mother', 'great-grandmother'); 920 case 'parfatpar': 921 return I18N::translateContext('parent’s father’s parent', 'great-grandparent'); 922 case 'parfatsib': 923 return I18N::translateContext('parent’s father’s sibling', 'great-aunt/uncle'); 924 case 'parfatsis': 925 return I18N::translateContext('parent’s father’s sister', 'great-aunt'); 926 case 'parmotbro': 927 return I18N::translateContext('parent’s mother’s brother', 'great-uncle'); 928 case 'parmotfat': 929 return I18N::translateContext('parent’s mother’s father', 'great-grandfather'); 930 case 'parmotmot': 931 return I18N::translateContext('parent’s mother’s mother', 'great-grandmother'); 932 case 'parmotpar': 933 return I18N::translateContext('parent’s mother’s parent', 'great-grandparent'); 934 case 'parmotsib': 935 return I18N::translateContext('parent’s mother’s sibling', 'great-aunt/uncle'); 936 case 'parmotsis': 937 return I18N::translateContext('parent’s mother’s sister', 'great-aunt'); 938 case 'parparbro': 939 return I18N::translateContext('parent’s parent’s brother', 'great-uncle'); 940 case 'parparfat': 941 return I18N::translateContext('parent’s parent’s father', 'great-grandfather'); 942 case 'parparmot': 943 return I18N::translateContext('parent’s parent’s mother', 'great-grandmother'); 944 case 'parparpar': 945 return I18N::translateContext('parent’s parent’s parent', 'great-grandparent'); 946 case 'parparsib': 947 return I18N::translateContext('parent’s parent’s sibling', 'great-aunt/uncle'); 948 case 'parparsis': 949 return I18N::translateContext('parent’s parent’s sister', 'great-aunt'); 950 case 'parsishus': 951 return I18N::translateContext('parent’s sister’s husband', 'uncle'); 952 case 'parspochi': 953 return I18N::translateContext('parent’s spouse’s child', 'step-sibling'); 954 case 'parspodau': 955 return I18N::translateContext('parent’s spouse’s daughter', 'step-sister'); 956 case 'parsposon': 957 return I18N::translateContext('parent’s spouse’s son', 'step-brother'); 958 case 'sibchichi': 959 return I18N::translateContext('sibling’s child’s child', 'great-nephew/niece'); 960 case 'sibchidau': 961 return I18N::translateContext('sibling’s child’s daughter', 'great-niece'); 962 case 'sibchison': 963 return I18N::translateContext('sibling’s child’s son', 'great-nephew'); 964 case 'sibdauchi': 965 return I18N::translateContext('sibling’s daughter’s child', 'great-nephew/niece'); 966 case 'sibdaudau': 967 return I18N::translateContext('sibling’s daughter’s daughter', 'great-niece'); 968 case 'sibdauhus': 969 return I18N::translateContext('sibling’s daughter’s husband', 'nephew-in-law'); 970 case 'sibdauson': 971 return I18N::translateContext('sibling’s daughter’s son', 'great-nephew'); 972 case 'sibsonchi': 973 return I18N::translateContext('sibling’s son’s child', 'great-nephew/niece'); 974 case 'sibsondau': 975 return I18N::translateContext('sibling’s son’s daughter', 'great-niece'); 976 case 'sibsonson': 977 return I18N::translateContext('sibling’s son’s son', 'great-nephew'); 978 case 'sibsonwif': 979 return I18N::translateContext('sibling’s son’s wife', 'niece-in-law'); 980 case 'sischichi': 981 if ($sex1 === 'M') { 982 return I18N::translateContext('(a man’s) sister’s child’s child', 'great-nephew/niece'); 983 } 984 985 return I18N::translateContext('(a woman’s) sister’s child’s child', 'great-nephew/niece'); 986 case 'sischidau': 987 if ($sex1 === 'M') { 988 return I18N::translateContext('(a man’s) sister’s child’s daughter', 'great-niece'); 989 } 990 991 return I18N::translateContext('(a woman’s) sister’s child’s daughter', 'great-niece'); 992 case 'sischison': 993 if ($sex1 === 'M') { 994 return I18N::translateContext('(a man’s) sister’s child’s son', 'great-nephew'); 995 } 996 997 return I18N::translateContext('(a woman’s) sister’s child’s son', 'great-nephew'); 998 case 'sisdauchi': 999 if ($sex1 === 'M') { 1000 return I18N::translateContext('(a man’s) sister’s daughter’s child', 'great-nephew/niece'); 1001 } 1002 1003 return I18N::translateContext('(a woman’s) sister’s daughter’s child', 'great-nephew/niece'); 1004 case 'sisdaudau': 1005 if ($sex1 === 'M') { 1006 return I18N::translateContext('(a man’s) sister’s daughter’s daughter', 'great-niece'); 1007 } 1008 1009 return I18N::translateContext('(a woman’s) sister’s daughter’s daughter', 'great-niece'); 1010 case 'sisdauhus': 1011 return I18N::translateContext('sisters’s daughter’s husband', 'nephew-in-law'); 1012 case 'sisdauson': 1013 if ($sex1 === 'M') { 1014 return I18N::translateContext('(a man’s) sister’s daughter’s son', 'great-nephew'); 1015 } 1016 1017 return I18N::translateContext('(a woman’s) sister’s daughter’s son', 'great-nephew'); 1018 case 'sishusbro': 1019 return I18N::translateContext('sister’s husband’s brother', 'brother-in-law'); 1020 case 'sishussib': 1021 return I18N::translateContext('sister’s husband’s sibling', 'brother/sister-in-law'); 1022 case 'sishussis': 1023 return I18N::translateContext('sister’s husband’s sister', 'sister-in-law'); 1024 case 'sissonchi': 1025 if ($sex1 === 'M') { 1026 return I18N::translateContext('(a man’s) sister’s son’s child', 'great-nephew/niece'); 1027 } 1028 1029 return I18N::translateContext('(a woman’s) sister’s son’s child', 'great-nephew/niece'); 1030 case 'sissondau': 1031 if ($sex1 === 'M') { 1032 return I18N::translateContext('(a man’s) sister’s son’s daughter', 'great-niece'); 1033 } 1034 1035 return I18N::translateContext('(a woman’s) sister’s son’s daughter', 'great-niece'); 1036 case 'sissonson': 1037 if ($sex1 === 'M') { 1038 return I18N::translateContext('(a man’s) sister’s son’s son', 'great-nephew'); 1039 } 1040 1041 return I18N::translateContext('(a woman’s) sister’s son’s son', 'great-nephew'); 1042 case 'sissonwif': 1043 return I18N::translateContext('sisters’s son’s wife', 'niece-in-law'); 1044 case 'sonchichi': 1045 return I18N::translateContext('son’s child’s child', 'great-grandchild'); 1046 case 'sonchidau': 1047 return I18N::translateContext('son’s child’s daughter', 'great-granddaughter'); 1048 case 'sonchison': 1049 return I18N::translateContext('son’s child’s son', 'great-grandson'); 1050 case 'sondauchi': 1051 return I18N::translateContext('son’s daughter’s child', 'great-grandchild'); 1052 case 'sondaudau': 1053 return I18N::translateContext('son’s daughter’s daughter', 'great-granddaughter'); 1054 case 'sondauhus': 1055 return I18N::translateContext('son’s daughter’s husband', 'granddaughter’s husband'); 1056 case 'sondauson': 1057 return I18N::translateContext('son’s daughter’s son', 'great-grandson'); 1058 case 'sonsonchi': 1059 return I18N::translateContext('son’s son’s child', 'great-grandchild'); 1060 case 'sonsondau': 1061 return I18N::translateContext('son’s son’s daughter', 'great-granddaughter'); 1062 case 'sonsonson': 1063 return I18N::translateContext('son’s son’s son', 'great-grandson'); 1064 case 'sonsonwif': 1065 return I18N::translateContext('son’s son’s wife', 'grandson’s wife'); 1066 case 'sonwiffat': 1067 return I18N::translateContext('son’s wife’s father', 'daughter-in-law’s father'); 1068 case 'sonwifmot': 1069 return I18N::translateContext('son’s wife’s mother', 'daughter-in-law’s mother'); 1070 case 'sonwifpar': 1071 return I18N::translateContext('son’s wife’s parent', 'daughter-in-law’s parent'); 1072 case 'wifbrowif': 1073 return I18N::translateContext('wife’s brother’s wife', 'sister-in-law'); 1074 case 'wifsishus': 1075 return I18N::translateContext('wife’s sister’s husband', 'brother-in-law'); 1076 case 'wifsibchi': 1077 return I18N::translateContext('wife’s sibling’s child', 'nephew/niece'); 1078 case 'wifsischi': 1079 return I18N::translateContext('wife’s sister’s child', 'nephew/niece'); 1080 case 'wifbrochi': 1081 return I18N::translateContext('wife’s brother’s child', 'nephew/niece'); 1082 case 'wifsibdau': 1083 return I18N::translateContext('wife’s sibling’s daughter', 'niece'); 1084 case 'wifsisdau': 1085 return I18N::translateContext('wife’s sister’s daughter', 'niece'); 1086 case 'wifbrodau': 1087 return I18N::translateContext('wife’s brother’s daughter', 'niece'); 1088 case 'wifsibson': 1089 return I18N::translateContext('wife’s sibling’s son', 'nephew'); 1090 case 'wifsisson': 1091 return I18N::translateContext('wife’s sister’s son', 'nephew'); 1092 case 'wifbroson': 1093 return I18N::translateContext('wife’s brother’s son', 'nephew'); 1094 1095 // Some “special case” level four relationships that have specific names in certain languages 1096 case 'fatfatbrowif': 1097 return I18N::translateContext('father’s father’s brother’s wife', 'great-aunt'); 1098 case 'fatfatsibspo': 1099 return I18N::translateContext('father’s father’s sibling’s spouse', 'great-aunt/uncle'); 1100 case 'fatfatsishus': 1101 return I18N::translateContext('father’s father’s sister’s husband', 'great-uncle'); 1102 case 'fatmotbrowif': 1103 return I18N::translateContext('father’s mother’s brother’s wife', 'great-aunt'); 1104 case 'fatmotsibspo': 1105 return I18N::translateContext('father’s mother’s sibling’s spouse', 'great-aunt/uncle'); 1106 case 'fatmotsishus': 1107 return I18N::translateContext('father’s mother’s sister’s husband', 'great-uncle'); 1108 case 'fatparbrowif': 1109 return I18N::translateContext('father’s parent’s brother’s wife', 'great-aunt'); 1110 case 'fatparsibspo': 1111 return I18N::translateContext('father’s parent’s sibling’s spouse', 'great-aunt/uncle'); 1112 case 'fatparsishus': 1113 return I18N::translateContext('father’s parent’s sister’s husband', 'great-uncle'); 1114 case 'motfatbrowif': 1115 return I18N::translateContext('mother’s father’s brother’s wife', 'great-aunt'); 1116 case 'motfatsibspo': 1117 return I18N::translateContext('mother’s father’s sibling’s spouse', 'great-aunt/uncle'); 1118 case 'motfatsishus': 1119 return I18N::translateContext('mother’s father’s sister’s husband', 'great-uncle'); 1120 case 'motmotbrowif': 1121 return I18N::translateContext('mother’s mother’s brother’s wife', 'great-aunt'); 1122 case 'motmotsibspo': 1123 return I18N::translateContext('mother’s mother’s sibling’s spouse', 'great-aunt/uncle'); 1124 case 'motmotsishus': 1125 return I18N::translateContext('mother’s mother’s sister’s husband', 'great-uncle'); 1126 case 'motparbrowif': 1127 return I18N::translateContext('mother’s parent’s brother’s wife', 'great-aunt'); 1128 case 'motparsibspo': 1129 return I18N::translateContext('mother’s parent’s sibling’s spouse', 'great-aunt/uncle'); 1130 case 'motparsishus': 1131 return I18N::translateContext('mother’s parent’s sister’s husband', 'great-uncle'); 1132 case 'parfatbrowif': 1133 return I18N::translateContext('parent’s father’s brother’s wife', 'great-aunt'); 1134 case 'parfatsibspo': 1135 return I18N::translateContext('parent’s father’s sibling’s spouse', 'great-aunt/uncle'); 1136 case 'parfatsishus': 1137 return I18N::translateContext('parent’s father’s sister’s husband', 'great-uncle'); 1138 case 'parmotbrowif': 1139 return I18N::translateContext('parent’s mother’s brother’s wife', 'great-aunt'); 1140 case 'parmotsibspo': 1141 return I18N::translateContext('parent’s mother’s sibling’s spouse', 'great-aunt/uncle'); 1142 case 'parmotsishus': 1143 return I18N::translateContext('parent’s mother’s sister’s husband', 'great-uncle'); 1144 case 'parparbrowif': 1145 return I18N::translateContext('parent’s parent’s brother’s wife', 'great-aunt'); 1146 case 'parparsibspo': 1147 return I18N::translateContext('parent’s parent’s sibling’s spouse', 'great-aunt/uncle'); 1148 case 'parparsishus': 1149 return I18N::translateContext('parent’s parent’s sister’s husband', 'great-uncle'); 1150 case 'fatfatbrodau': 1151 return I18N::translateContext('father’s father’s brother’s daughter', 'first cousin once removed ascending'); 1152 case 'fatfatbroson': 1153 return I18N::translateContext('father’s father’s brother’s son', 'first cousin once removed ascending'); 1154 case 'fatfatbrochi': 1155 return I18N::translateContext('father’s father’s brother’s child', 'first cousin once removed ascending'); 1156 case 'fatfatsisdau': 1157 return I18N::translateContext('father’s father’s sister’s daughter', 'first cousin once removed ascending'); 1158 case 'fatfatsisson': 1159 return I18N::translateContext('father’s father’s sister’s son', 'first cousin once removed ascending'); 1160 case 'fatfatsischi': 1161 return I18N::translateContext('father’s father’s sister’s child', 'first cousin once removed ascending'); 1162 case 'fatmotbrodau': 1163 return I18N::translateContext('father’s mother’s brother’s daughter', 'first cousin once removed ascending'); 1164 case 'fatmotbroson': 1165 return I18N::translateContext('father’s mother’s brother’s son', 'first cousin once removed ascending'); 1166 case 'fatmotbrochi': 1167 return I18N::translateContext('father’s mother’s brother’s child', 'first cousin once removed ascending'); 1168 case 'fatmotsisdau': 1169 return I18N::translateContext('father’s mother’s sister’s daughter', 'first cousin once removed ascending'); 1170 case 'fatmotsisson': 1171 return I18N::translateContext('father’s mother’s sister’s son', 'first cousin once removed ascending'); 1172 case 'fatmotsischi': 1173 return I18N::translateContext('father’s mother’s sister’s child', 'first cousin once removed ascending'); 1174 case 'motfatbrodau': 1175 return I18N::translateContext('mother’s father’s brother’s daughter', 'first cousin once removed ascending'); 1176 case 'motfatbroson': 1177 return I18N::translateContext('mother’s father’s brother’s son', 'first cousin once removed ascending'); 1178 case 'motfatbrochi': 1179 return I18N::translateContext('mother’s father’s brother’s child', 'first cousin once removed ascending'); 1180 case 'motfatsisdau': 1181 return I18N::translateContext('mother’s father’s sister’s daughter', 'first cousin once removed ascending'); 1182 case 'motfatsisson': 1183 return I18N::translateContext('mother’s father’s sister’s son', 'first cousin once removed ascending'); 1184 case 'motfatsischi': 1185 return I18N::translateContext('mother’s father’s sister’s child', 'first cousin once removed ascending'); 1186 case 'motmotbrodau': 1187 return I18N::translateContext('mother’s mother’s brother’s daughter', 'first cousin once removed ascending'); 1188 case 'motmotbroson': 1189 return I18N::translateContext('mother’s mother’s brother’s son', 'first cousin once removed ascending'); 1190 case 'motmotbrochi': 1191 return I18N::translateContext('mother’s mother’s brother’s child', 'first cousin once removed ascending'); 1192 case 'motmotsisdau': 1193 return I18N::translateContext('mother’s mother’s sister’s daughter', 'first cousin once removed ascending'); 1194 case 'motmotsisson': 1195 return I18N::translateContext('mother’s mother’s sister’s son', 'first cousin once removed ascending'); 1196 case 'motmotsischi': 1197 return I18N::translateContext('mother’s mother’s sister’s child', 'first cousin once removed ascending'); 1198 } 1199 1200 // Some “special case” level five relationships that have specific names in certain languages 1201 if (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)dau$/', $path)) { 1202 return I18N::translateContext('grandfather’s brother’s granddaughter', 'second cousin'); 1203 } 1204 1205 if (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)son$/', $path)) { 1206 return I18N::translateContext('grandfather’s brother’s grandson', 'second cousin'); 1207 } 1208 1209 if (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)chi$/', $path)) { 1210 return I18N::translateContext('grandfather’s brother’s grandchild', 'second cousin'); 1211 } 1212 1213 if (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)dau$/', $path)) { 1214 return I18N::translateContext('grandfather’s sister’s granddaughter', 'second cousin'); 1215 } 1216 1217 if (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)son$/', $path)) { 1218 return I18N::translateContext('grandfather’s sister’s grandson', 'second cousin'); 1219 } 1220 1221 if (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)chi$/', $path)) { 1222 return I18N::translateContext('grandfather’s sister’s grandchild', 'second cousin'); 1223 } 1224 1225 if (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)dau$/', $path)) { 1226 return I18N::translateContext('grandfather’s sibling’s granddaughter', 'second cousin'); 1227 } 1228 1229 if (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)son$/', $path)) { 1230 return I18N::translateContext('grandfather’s sibling’s grandson', 'second cousin'); 1231 } 1232 1233 if (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)chi$/', $path)) { 1234 return I18N::translateContext('grandfather’s sibling’s grandchild', 'second cousin'); 1235 } 1236 1237 if (preg_match('/^(mot|fat|par)motbro(son|dau|chi)dau$/', $path)) { 1238 return I18N::translateContext('grandmother’s brother’s granddaughter', 'second cousin'); 1239 } 1240 1241 if (preg_match('/^(mot|fat|par)motbro(son|dau|chi)son$/', $path)) { 1242 return I18N::translateContext('grandmother’s brother’s grandson', 'second cousin'); 1243 } 1244 1245 if (preg_match('/^(mot|fat|par)motbro(son|dau|chi)chi$/', $path)) { 1246 return I18N::translateContext('grandmother’s brother’s grandchild', 'second cousin'); 1247 } 1248 1249 if (preg_match('/^(mot|fat|par)motsis(son|dau|chi)dau$/', $path)) { 1250 return I18N::translateContext('grandmother’s sister’s granddaughter', 'second cousin'); 1251 } 1252 1253 if (preg_match('/^(mot|fat|par)motsis(son|dau|chi)son$/', $path)) { 1254 return I18N::translateContext('grandmother’s sister’s grandson', 'second cousin'); 1255 } 1256 1257 if (preg_match('/^(mot|fat|par)motsis(son|dau|chi)chi$/', $path)) { 1258 return I18N::translateContext('grandmother’s sister’s grandchild', 'second cousin'); 1259 } 1260 1261 if (preg_match('/^(mot|fat|par)motsib(son|dau|chi)dau$/', $path)) { 1262 return I18N::translateContext('grandmother’s sibling’s granddaughter', 'second cousin'); 1263 } 1264 1265 if (preg_match('/^(mot|fat|par)motsib(son|dau|chi)son$/', $path)) { 1266 return I18N::translateContext('grandmother’s sibling’s grandson', 'second cousin'); 1267 } 1268 1269 if (preg_match('/^(mot|fat|par)motsib(son|dau|chi)chi$/', $path)) { 1270 return I18N::translateContext('grandmother’s sibling’s grandchild', 'second cousin'); 1271 } 1272 1273 if (preg_match('/^(mot|fat|par)parbro(son|dau|chi)dau$/', $path)) { 1274 return I18N::translateContext('grandparent’s brother’s granddaughter', 'second cousin'); 1275 } 1276 1277 if (preg_match('/^(mot|fat|par)parbro(son|dau|chi)son$/', $path)) { 1278 return I18N::translateContext('grandparent’s brother’s grandson', 'second cousin'); 1279 } 1280 1281 if (preg_match('/^(mot|fat|par)parbro(son|dau|chi)chi$/', $path)) { 1282 return I18N::translateContext('grandparent’s brother’s grandchild', 'second cousin'); 1283 } 1284 1285 if (preg_match('/^(mot|fat|par)parsis(son|dau|chi)dau$/', $path)) { 1286 return I18N::translateContext('grandparent’s sister’s granddaughter', 'second cousin'); 1287 } 1288 1289 if (preg_match('/^(mot|fat|par)parsis(son|dau|chi)son$/', $path)) { 1290 return I18N::translateContext('grandparent’s sister’s grandson', 'second cousin'); 1291 } 1292 1293 if (preg_match('/^(mot|fat|par)parsis(son|dau|chi)chi$/', $path)) { 1294 return I18N::translateContext('grandparent’s sister’s grandchild', 'second cousin'); 1295 } 1296 1297 if (preg_match('/^(mot|fat|par)parsib(son|dau|chi)dau$/', $path)) { 1298 return I18N::translateContext('grandparent’s sibling’s granddaughter', 'second cousin'); 1299 } 1300 1301 if (preg_match('/^(mot|fat|par)parsib(son|dau|chi)son$/', $path)) { 1302 return I18N::translateContext('grandparent’s sibling’s grandson', 'second cousin'); 1303 } 1304 1305 if (preg_match('/^(mot|fat|par)parsib(son|dau|chi)chi$/', $path)) { 1306 return I18N::translateContext('grandparent’s sibling’s grandchild', 'second cousin'); 1307 } 1308 1309 // Look for generic/pattern relationships. 1310 if (preg_match('/^((?:mot|fat|par)+)(bro|sis|sib)$/', $path, $match)) { 1311 // siblings of direct ancestors 1312 $up = intdiv(strlen($match[1]), 3); 1313 $bef_last = substr($path, -6, 3); 1314 switch ($up) { 1315 case 3: 1316 if ($sex2 === 'M') { 1317 if ($bef_last === 'fat') { 1318 return I18N::translateContext('great-grandfather’s brother', 'great-great-uncle'); 1319 } 1320 1321 if ($bef_last === 'mot') { 1322 return I18N::translateContext('great-grandmother’s brother', 'great-great-uncle'); 1323 } 1324 1325 return I18N::translateContext('great-grandparent’s brother', 'great-great-uncle'); 1326 } 1327 1328 if ($sex2 === 'F') { 1329 return I18N::translate('great-great-aunt'); 1330 } 1331 1332 return I18N::translate('great-great-aunt/uncle'); 1333 1334 case 4: 1335 if ($sex2 === 'M') { 1336 if ($bef_last === 'fat') { 1337 return I18N::translateContext('great-great-grandfather’s brother', 'great-great-great-uncle'); 1338 } 1339 1340 if ($bef_last === 'mot') { 1341 return I18N::translateContext('great-great-grandmother’s brother', 'great-great-great-uncle'); 1342 } 1343 1344 return I18N::translateContext('great-great-grandparent’s brother', 'great-great-great-uncle'); 1345 } 1346 1347 if ($sex2 === 'F') { 1348 return I18N::translate('great-great-great-aunt'); 1349 } 1350 1351 return I18N::translate('great-great-great-aunt/uncle'); 1352 1353 case 5: 1354 if ($sex2 === 'M') { 1355 if ($bef_last === 'fat') { 1356 return I18N::translateContext('great-great-great-grandfather’s brother', 'great ×4 uncle'); 1357 } 1358 1359 if ($bef_last === 'mot') { 1360 return I18N::translateContext('great-great-great-grandmother’s brother', 'great ×4 uncle'); 1361 } 1362 1363 return I18N::translateContext('great-great-great-grandparent’s brother', 'great ×4 uncle'); 1364 } 1365 1366 if ($sex2 === 'F') { 1367 return I18N::translate('great ×4 aunt'); 1368 } 1369 1370 return I18N::translate('great ×4 aunt/uncle'); 1371 1372 case 6: 1373 if ($sex2 === 'M') { 1374 if ($bef_last === 'fat') { 1375 return I18N::translateContext('great ×4 grandfather’s brother', 'great ×5 uncle'); 1376 } 1377 1378 if ($bef_last === 'mot') { 1379 return I18N::translateContext('great ×4 grandmother’s brother', 'great ×5 uncle'); 1380 } 1381 1382 return I18N::translateContext('great ×4 grandparent’s brother', 'great ×5 uncle'); 1383 } 1384 1385 if ($sex2 === 'F') { 1386 return I18N::translate('great ×5 aunt'); 1387 } 1388 1389 return I18N::translate('great ×5 aunt/uncle'); 1390 1391 case 7: 1392 if ($sex2 === 'M') { 1393 if ($bef_last === 'fat') { 1394 return I18N::translateContext('great ×5 grandfather’s brother', 'great ×6 uncle'); 1395 } 1396 1397 if ($bef_last === 'mot') { 1398 return I18N::translateContext('great ×5 grandmother’s brother', 'great ×6 uncle'); 1399 } 1400 1401 return I18N::translateContext('great ×5 grandparent’s brother', 'great ×6 uncle'); 1402 } 1403 1404 if ($sex2 === 'F') { 1405 return I18N::translate('great ×6 aunt'); 1406 } 1407 1408 return I18N::translate('great ×6 aunt/uncle'); 1409 1410 case 8: 1411 if ($sex2 === 'M') { 1412 if ($bef_last === 'fat') { 1413 return I18N::translateContext('great ×6 grandfather’s brother', 'great ×7 uncle'); 1414 } 1415 1416 if ($bef_last === 'mot') { 1417 return I18N::translateContext('great ×6 grandmother’s brother', 'great ×7 uncle'); 1418 } 1419 1420 return I18N::translateContext('great ×6 grandparent’s brother', 'great ×7 uncle'); 1421 } 1422 1423 if ($sex2 === 'F') { 1424 return I18N::translate('great ×7 aunt'); 1425 } 1426 1427 return I18N::translate('great ×7 aunt/uncle'); 1428 1429 default: 1430 // Different languages have different rules for naming generations. 1431 // An English great ×12 uncle is a Danish great ×10 uncle. 1432 // 1433 // Need to find out which languages use which rules. 1434 switch (I18N::languageTag()) { 1435 case 'da': 1436 if ($sex2 === 'M') { 1437 return I18N::translate('great ×%s uncle', I18N::number($up - 4)); 1438 } 1439 1440 if ($sex2 === 'F') { 1441 return I18N::translate('great ×%s aunt', I18N::number($up - 4)); 1442 } 1443 1444 return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 4)); 1445 1446 case 'pl': 1447 if ($sex2 === 'M') { 1448 if ($bef_last === 'fat') { 1449 return I18N::translateContext('great ×(%s-1) grandfather’s brother', 'great ×%s uncle', I18N::number($up - 2)); 1450 } 1451 1452 if ($bef_last === 'mot') { 1453 return I18N::translateContext('great ×(%s-1) grandmother’s brother', 'great ×%s uncle', I18N::number($up - 2)); 1454 } 1455 1456 return I18N::translateContext('great ×(%s-1) grandparent’s brother', 'great ×%s uncle', I18N::number($up - 2)); 1457 } 1458 1459 if ($sex2 === 'F') { 1460 return I18N::translate('great ×%s aunt', I18N::number($up - 2)); 1461 } 1462 1463 return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 2)); 1464 1465 case 'ko': // Source : Jeongwan Nam (jeongwann@gmail.com) 1466 if ($sex2 === 'M') { 1467 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1468 return I18N::translate('great ×%s uncle', I18N::number($up + 1)); 1469 } 1470 1471 if ($sex2 === 'F') { 1472 return I18N::translate('great ×%s aunt', I18N::number($up + 1)); 1473 } 1474 1475 return I18N::translate('great ×%s aunt/uncle', I18N::number($up + 1)); 1476 1477 case 'hi': // Source: MrQD 1478 if ($sex2 === 'M') { 1479 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1480 return I18N::translate('great ×%s uncle', I18N::number($up - 2)); 1481 } 1482 1483 if ($sex2 === 'F') { 1484 return I18N::translate('great ×%s aunt', I18N::number($up - 2)); 1485 } 1486 1487 return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 2)); 1488 1489 case 'zh-Hans': // Source: xmlf 1490 case 'zh-Hant': 1491 if ($sex2 === 'M') { 1492 return I18N::translate('great ×%s uncle', I18N::number($up)); 1493 } 1494 if ($sex2 === 'F') { 1495 return I18N::translate('great ×%s aunt', I18N::number($up)); 1496 } 1497 1498 return I18N::translate('great ×%s aunt/uncle', I18N::number($up)); 1499 1500 case 'it': // Source: Michele Locati 1501 case 'en_AU': 1502 case 'en_GB': 1503 case 'en_US': 1504 default: 1505 if ($sex2 === 'M') { 1506 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1507 return I18N::translate('great ×%s uncle', I18N::number($up - 1)); 1508 } 1509 1510 if ($sex2 === 'F') { 1511 return I18N::translate('great ×%s aunt', I18N::number($up - 1)); 1512 } 1513 1514 return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 1)); 1515 } 1516 } 1517 } 1518 if (preg_match('/^(?:bro|sis|sib)((?:son|dau|chi)+)$/', $path, $match)) { 1519 // direct descendants of siblings 1520 $down = intdiv(strlen($match[1]), 3) + 1; // Add one, as we count generations from the common ancestor 1521 $first = substr($path, 0, 3); 1522 switch ($down) { 1523 case 4: 1524 if ($sex2 === 'M') { 1525 if ($first === 'bro' && $sex1 === 'M') { 1526 return I18N::translateContext('(a man’s) brother’s great-grandson', 'great-great-nephew'); 1527 } 1528 1529 if ($first === 'sis' && $sex1 === 'M') { 1530 return I18N::translateContext('(a man’s) sister’s great-grandson', 'great-great-nephew'); 1531 } 1532 1533 return I18N::translateContext('(a woman’s) great-great-nephew', 'great-great-nephew'); 1534 } 1535 1536 if ($sex2 === 'F') { 1537 if ($first === 'bro' && $sex1 === 'M') { 1538 return I18N::translateContext('(a man’s) brother’s great-granddaughter', 'great-great-niece'); 1539 } 1540 1541 if ($first === 'sis' && $sex1 === 'M') { 1542 return I18N::translateContext('(a man’s) sister’s great-granddaughter', 'great-great-niece'); 1543 } 1544 1545 return I18N::translateContext('(a woman’s) great-great-niece', 'great-great-niece'); 1546 } 1547 1548 if ($first === 'bro' && $sex1 === 'M') { 1549 return I18N::translateContext('(a man’s) brother’s great-grandchild', 'great-great-nephew/niece'); 1550 } 1551 1552 if ($first === 'sis' && $sex1 === 'M') { 1553 return I18N::translateContext('(a man’s) sister’s great-grandchild', 'great-great-nephew/niece'); 1554 } 1555 1556 return I18N::translateContext('(a woman’s) great-great-nephew/niece', 'great-great-nephew/niece'); 1557 1558 case 5: 1559 if ($sex2 === 'M') { 1560 if ($first === 'bro' && $sex1 === 'M') { 1561 return I18N::translateContext('(a man’s) brother’s great-great-grandson', 'great-great-great-nephew'); 1562 } 1563 1564 if ($first === 'sis' && $sex1 === 'M') { 1565 return I18N::translateContext('(a man’s) sister’s great-great-grandson', 'great-great-great-nephew'); 1566 } 1567 1568 return I18N::translateContext('(a woman’s) great-great-great-nephew', 'great-great-great-nephew'); 1569 } 1570 1571 if ($sex2 === 'F') { 1572 if ($first === 'bro' && $sex1 === 'M') { 1573 return I18N::translateContext('(a man’s) brother’s great-great-granddaughter', 'great-great-great-niece'); 1574 } 1575 1576 if ($first === 'sis' && $sex1 === 'M') { 1577 return I18N::translateContext('(a man’s) sister’s great-great-granddaughter', 'great-great-great-niece'); 1578 } 1579 1580 return I18N::translateContext('(a woman’s) great-great-great-niece', 'great-great-great-niece'); 1581 } 1582 1583 if ($first === 'bro' && $sex1 === 'M') { 1584 return I18N::translateContext('(a man’s) brother’s great-great-grandchild', 'great-great-great-nephew/niece'); 1585 } 1586 1587 if ($first === 'sis' && $sex1 === 'M') { 1588 return I18N::translateContext('(a man’s) sister’s great-great-grandchild', 'great-great-great-nephew/niece'); 1589 } 1590 1591 return I18N::translateContext('(a woman’s) great-great-great-nephew/niece', 'great-great-great-nephew/niece'); 1592 1593 case 6: 1594 if ($sex2 === 'M') { 1595 if ($first === 'bro' && $sex1 === 'M') { 1596 return I18N::translateContext('(a man’s) brother’s great-great-great-grandson', 'great ×4 nephew'); 1597 } 1598 1599 if ($first === 'sis' && $sex1 === 'M') { 1600 return I18N::translateContext('(a man’s) sister’s great-great-great-grandson', 'great ×4 nephew'); 1601 } 1602 1603 return I18N::translateContext('(a woman’s) great ×4 nephew', 'great ×4 nephew'); 1604 } 1605 1606 if ($sex2 === 'F') { 1607 if ($first === 'bro' && $sex1 === 'M') { 1608 return I18N::translateContext('(a man’s) brother’s great-great-great-granddaughter', 'great ×4 niece'); 1609 } 1610 1611 if ($first === 'sis' && $sex1 === 'M') { 1612 return I18N::translateContext('(a man’s) sister’s great-great-great-granddaughter', 'great ×4 niece'); 1613 } 1614 1615 return I18N::translateContext('(a woman’s) great ×4 niece', 'great ×4 niece'); 1616 } 1617 1618 if ($first === 'bro' && $sex1 === 'M') { 1619 return I18N::translateContext('(a man’s) brother’s great-great-great-grandchild', 'great ×4 nephew/niece'); 1620 } 1621 1622 if ($first === 'sis' && $sex1 === 'M') { 1623 return I18N::translateContext('(a man’s) sister’s great-great-great-grandchild', 'great ×4 nephew/niece'); 1624 } 1625 1626 return I18N::translateContext('(a woman’s) great ×4 nephew/niece', 'great ×4 nephew/niece'); 1627 1628 case 7: 1629 if ($sex2 === 'M') { 1630 if ($first === 'bro' && $sex1 === 'M') { 1631 return I18N::translateContext('(a man’s) brother’s great ×4 grandson', 'great ×5 nephew'); 1632 } 1633 1634 if ($first === 'sis' && $sex1 === 'M') { 1635 return I18N::translateContext('(a man’s) sister’s great ×4 grandson', 'great ×5 nephew'); 1636 } 1637 1638 return I18N::translateContext('(a woman’s) great ×5 nephew', 'great ×5 nephew'); 1639 } 1640 1641 if ($sex2 === 'F') { 1642 if ($first === 'bro' && $sex1 === 'M') { 1643 return I18N::translateContext('(a man’s) brother’s great ×4 granddaughter', 'great ×5 niece'); 1644 } 1645 1646 if ($first === 'sis' && $sex1 === 'M') { 1647 return I18N::translateContext('(a man’s) sister’s great ×4 granddaughter', 'great ×5 niece'); 1648 } 1649 1650 return I18N::translateContext('(a woman’s) great ×5 niece', 'great ×5 niece'); 1651 } 1652 1653 if ($first === 'bro' && $sex1 === 'M') { 1654 return I18N::translateContext('(a man’s) brother’s great ×4 grandchild', 'great ×5 nephew/niece'); 1655 } 1656 1657 if ($first === 'sis' && $sex1 === 'M') { 1658 return I18N::translateContext('(a man’s) sister’s great ×4 grandchild', 'great ×5 nephew/niece'); 1659 } 1660 1661 return I18N::translateContext('(a woman’s) great ×5 nephew/niece', 'great ×5 nephew/niece'); 1662 1663 default: 1664 // Different languages have different rules for naming generations. 1665 // An English great ×12 nephew is a Polish great ×11 nephew. 1666 // 1667 // Need to find out which languages use which rules. 1668 switch (I18N::languageTag()) { 1669 case 'pl': // Source: Lukasz Wilenski 1670 if ($sex2 === 'M') { 1671 if ($first === 'bro' && $sex1 === 'M') { 1672 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 3)); 1673 } 1674 1675 if ($first === 'sis' && $sex1 === 'M') { 1676 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 3)); 1677 } 1678 1679 return I18N::translateContext('(a woman’s) great ×%s nephew', 'great ×%s nephew', I18N::number($down - 3)); 1680 } 1681 1682 if ($sex2 === 'F') { 1683 if ($first === 'bro' && $sex1 === 'M') { 1684 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 3)); 1685 } 1686 1687 if ($first === 'sis' && $sex1 === 'M') { 1688 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 3)); 1689 } 1690 1691 return I18N::translateContext('(a woman’s) great ×%s niece', 'great ×%s niece', I18N::number($down - 3)); 1692 } 1693 1694 if ($first === 'bro' && $sex1 === 'M') { 1695 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 3)); 1696 } 1697 1698 if ($first === 'sis' && $sex1 === 'M') { 1699 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 3)); 1700 } 1701 1702 return I18N::translateContext('(a woman’s) great ×%s nephew/niece', 'great ×%s nephew/niece', I18N::number($down - 3)); 1703 1704 case 'ko': // Source: Jeongwan Nam (jeongwann@gmail.com) 1705 if ($sex2 === 'M') { 1706 if ($first === 'bro' && $sex1 === 'M') { 1707 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 0)); 1708 } 1709 1710 if ($first === 'sis' && $sex1 === 'M') { 1711 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 0)); 1712 } 1713 1714 return I18N::translateContext('(a woman’s) great ×%s nephew', 'great ×%s nephew', I18N::number($down - 0)); 1715 } 1716 1717 if ($sex2 === 'F') { 1718 if ($first === 'bro' && $sex1 === 'M') { 1719 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 3)); 1720 } 1721 1722 if ($first === 'sis' && $sex1 === 'M') { 1723 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 3)); 1724 } 1725 1726 return I18N::translateContext('(a woman’s) great ×%s niece', 'great ×%s niece', I18N::number($down - 3)); 1727 } 1728 1729 if ($first === 'bro' && $sex1 === 'M') { 1730 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 3)); 1731 } 1732 1733 if ($first === 'sis' && $sex1 === 'M') { 1734 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 3)); 1735 } 1736 1737 return I18N::translateContext('(a woman’s) great ×%s nephew/niece', 'great ×%s nephew/niece', I18N::number($down - 3)); 1738 1739 case 'zh-Hans': // Source: xmlf 1740 case 'zh-Hant': 1741 if ($sex2 === 'M') { 1742 if ($first === 'bro' && $sex1 === 'M') { 1743 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 1)); 1744 } 1745 if ($first === 'sis' && $sex1 === 'M') { 1746 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 1)); 1747 } 1748 1749 return I18N::translateContext('(a woman’s) great ×%s nephew', 'great ×%s nephew', I18N::number($down - 1)); 1750 } 1751 if ($sex2 === 'F') { 1752 if ($first === 'bro' && $sex1 === 'M') { 1753 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 1)); 1754 } 1755 if ($first === 'sis' && $sex1 === 'M') { 1756 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 1)); 1757 } 1758 1759 return I18N::translateContext('(a woman’s) great ×%s niece', 'great ×%s niece', I18N::number($down - 1)); 1760 } 1761 if ($first === 'bro' && $sex1 === 'M') { 1762 return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 1)); 1763 } 1764 if ($first === 'sis' && $sex1 === 'M') { 1765 return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 1)); 1766 } 1767 1768 return I18N::translateContext('(a woman’s) great ×%s nephew/niece', 'great ×%s nephew/niece', I18N::number($down - 1)); 1769 1770 case 'he': // Source: Meliza Amity 1771 if ($sex2 === 'M') { 1772 return I18N::translate('great ×%s nephew', I18N::number($down - 1)); 1773 } 1774 1775 if ($sex2 === 'F') { 1776 return I18N::translate('great ×%s niece', I18N::number($down - 1)); 1777 } 1778 1779 return I18N::translate('great ×%s nephew/niece', I18N::number($down - 1)); 1780 1781 case 'hi': // Source: MrQD. 1782 if ($sex2 === 'M') { 1783 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1784 return I18N::translate('great ×%s nephew', I18N::number($down - 3)); 1785 } 1786 1787 if ($sex2 === 'F') { 1788 return I18N::translate('great ×%s niece', I18N::number($down - 3)); 1789 } 1790 1791 return I18N::translate('great ×%s nephew/niece', I18N::number($down - 3)); 1792 1793 case 'it': // Source: Michele Locati. 1794 case 'en_AU': 1795 case 'en_GB': 1796 case 'en_US': 1797 default: 1798 if ($sex2 === 'M') { 1799 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1800 return I18N::translate('great ×%s nephew', I18N::number($down - 2)); 1801 } 1802 1803 if ($sex2 === 'F') { 1804 return I18N::translate('great ×%s niece', I18N::number($down - 2)); 1805 } 1806 1807 return I18N::translate('great ×%s nephew/niece', I18N::number($down - 2)); 1808 } 1809 } 1810 } 1811 if (preg_match('/^((?:mot|fat|par)*)$/', $path, $match)) { 1812 // direct ancestors 1813 $up = intdiv(strlen($match[1]), 3); 1814 switch ($up) { 1815 case 4: 1816 if ($sex2 === 'M') { 1817 return I18N::translate('great-great-grandfather'); 1818 } 1819 1820 if ($sex2 === 'F') { 1821 return I18N::translate('great-great-grandmother'); 1822 } 1823 1824 return I18N::translate('great-great-grandparent'); 1825 1826 case 5: 1827 if ($sex2 === 'M') { 1828 return I18N::translate('great-great-great-grandfather'); 1829 } 1830 1831 if ($sex2 === 'F') { 1832 return I18N::translate('great-great-great-grandmother'); 1833 } 1834 1835 return I18N::translate('great-great-great-grandparent'); 1836 1837 case 6: 1838 if ($sex2 === 'M') { 1839 return I18N::translate('great ×4 grandfather'); 1840 } 1841 1842 if ($sex2 === 'F') { 1843 return I18N::translate('great ×4 grandmother'); 1844 } 1845 1846 return I18N::translate('great ×4 grandparent'); 1847 1848 case 7: 1849 if ($sex2 === 'M') { 1850 return I18N::translate('great ×5 grandfather'); 1851 } 1852 1853 if ($sex2 === 'F') { 1854 return I18N::translate('great ×5 grandmother'); 1855 } 1856 1857 return I18N::translate('great ×5 grandparent'); 1858 1859 case 8: 1860 if ($sex2 === 'M') { 1861 return I18N::translate('great ×6 grandfather'); 1862 } 1863 1864 if ($sex2 === 'F') { 1865 return I18N::translate('great ×6 grandmother'); 1866 } 1867 1868 return I18N::translate('great ×6 grandparent'); 1869 1870 case 9: 1871 if ($sex2 === 'M') { 1872 return I18N::translate('great ×7 grandfather'); 1873 } 1874 1875 if ($sex2 === 'F') { 1876 return I18N::translate('great ×7 grandmother'); 1877 } 1878 1879 return I18N::translate('great ×7 grandparent'); 1880 1881 default: 1882 // Different languages have different rules for naming generations. 1883 // An English great ×12 grandfather is a Danish great ×11 grandfather. 1884 // 1885 // Need to find out which languages use which rules. 1886 switch (I18N::languageTag()) { 1887 case 'da': // Source: Patrick Sorensen 1888 if ($sex2 === 'M') { 1889 return I18N::translate('great ×%s grandfather', I18N::number($up - 3)); 1890 } 1891 1892 if ($sex2 === 'F') { 1893 return I18N::translate('great ×%s grandmother', I18N::number($up - 3)); 1894 } 1895 1896 return I18N::translate('great ×%s grandparent', I18N::number($up - 3)); 1897 1898 case 'it': // Source: Michele Locati 1899 case 'zh-Hans': // Source: xmlf 1900 case 'zh-Hant': 1901 case 'es': // Source: Wes Groleau 1902 if ($sex2 === 'M') { 1903 return I18N::translate('great ×%s grandfather', I18N::number($up)); 1904 } 1905 1906 if ($sex2 === 'F') { 1907 return I18N::translate('great ×%s grandmother', I18N::number($up)); 1908 } 1909 1910 return I18N::translate('great ×%s grandparent', I18N::number($up)); 1911 1912 case 'fr': // Source: Jacqueline Tetreault 1913 case 'fr_CA': 1914 if ($sex2 === 'M') { 1915 return I18N::translate('great ×%s grandfather', I18N::number($up - 1)); 1916 } 1917 1918 if ($sex2 === 'F') { 1919 return I18N::translate('great ×%s grandmother', I18N::number($up - 1)); 1920 } 1921 1922 return I18N::translate('great ×%s grandparent', I18N::number($up - 1)); 1923 1924 case 'ko': // Source : Jeongwan Nam (jeongwann@gmail.com) 1925 if ($sex2 === 'M') { 1926 return I18N::translate('great ×%s grandfather', I18N::number($up + 1)); 1927 } 1928 1929 if ($sex2 === 'F') { 1930 return I18N::translate('great ×%s grandmother', I18N::number($up + 1)); 1931 } 1932 1933 return I18N::translate('great ×%s grandparent', I18N::number($up + 1)); 1934 1935 case 'nn': // Source: Hogne Røed Nilsen (https://bugs.launchpad.net/webtrees/+bug/1168553) 1936 case 'nb': 1937 if ($sex2 === 'M') { 1938 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1939 return I18N::translate('great ×%s grandfather', I18N::number($up - 3)); 1940 } 1941 1942 if ($sex2 === 'F') { 1943 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1944 return I18N::translate('great ×%s grandmother', I18N::number($up - 3)); 1945 } 1946 1947 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1948 return I18N::translate('great ×%s grandparent', I18N::number($up - 3)); 1949 case 'en_AU': 1950 case 'en_GB': 1951 case 'en_US': 1952 default: 1953 if ($sex2 === 'M') { 1954 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1955 return I18N::translate('great ×%s grandfather', I18N::number($up - 2)); 1956 } 1957 1958 if ($sex2 === 'F') { 1959 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1960 return I18N::translate('great ×%s grandmother', I18N::number($up - 2)); 1961 } 1962 1963 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 1964 return I18N::translate('great ×%s grandparent', I18N::number($up - 2)); 1965 } 1966 } 1967 } 1968 if (preg_match('/^((?:son|dau|chi)*)$/', $path, $match)) { 1969 // direct descendants 1970 $up = intdiv(strlen($match[1]), 3); 1971 switch ($up) { 1972 case 4: 1973 if ($sex2 === 'M') { 1974 return I18N::translate('great-great-grandson'); 1975 } 1976 1977 if ($sex2 === 'F') { 1978 return I18N::translate('great-great-granddaughter'); 1979 } 1980 1981 return I18N::translate('great-great-grandchild'); 1982 1983 case 5: 1984 if ($sex2 === 'M') { 1985 return I18N::translate('great-great-great-grandson'); 1986 } 1987 1988 if ($sex2 === 'F') { 1989 return I18N::translate('great-great-great-granddaughter'); 1990 } 1991 1992 return I18N::translate('great-great-great-grandchild'); 1993 1994 case 6: 1995 if ($sex2 === 'M') { 1996 return I18N::translate('great ×4 grandson'); 1997 } 1998 1999 if ($sex2 === 'F') { 2000 return I18N::translate('great ×4 granddaughter'); 2001 } 2002 2003 return I18N::translate('great ×4 grandchild'); 2004 2005 case 7: 2006 if ($sex2 === 'M') { 2007 return I18N::translate('great ×5 grandson'); 2008 } 2009 2010 if ($sex2 === 'F') { 2011 return I18N::translate('great ×5 granddaughter'); 2012 } 2013 2014 return I18N::translate('great ×5 grandchild'); 2015 2016 case 8: 2017 if ($sex2 === 'M') { 2018 return I18N::translate('great ×6 grandson'); 2019 } 2020 2021 if ($sex2 === 'F') { 2022 return I18N::translate('great ×6 granddaughter'); 2023 } 2024 2025 return I18N::translate('great ×6 grandchild'); 2026 2027 case 9: 2028 if ($sex2 === 'M') { 2029 return I18N::translate('great ×7 grandson'); 2030 } 2031 2032 if ($sex2 === 'F') { 2033 return I18N::translate('great ×7 granddaughter'); 2034 } 2035 2036 return I18N::translate('great ×7 grandchild'); 2037 2038 default: 2039 // Different languages have different rules for naming generations. 2040 // An English great ×12 grandson is a Danish great ×11 grandson. 2041 // 2042 // Need to find out which languages use which rules. 2043 switch (I18N::languageTag()) { 2044 case 'nn': // Source: Hogne Røed Nilsen 2045 case 'nb': 2046 case 'da': // Source: Patrick Sorensen 2047 if ($sex2 === 'M') { 2048 return I18N::translate('great ×%s grandson', I18N::number($up - 3)); 2049 } 2050 2051 if ($sex2 === 'F') { 2052 return I18N::translate('great ×%s granddaughter', I18N::number($up - 3)); 2053 } 2054 2055 return I18N::translate('great ×%s grandchild', I18N::number($up - 3)); 2056 2057 case 'ko': // Source : Jeongwan Nam (jeongwann@gmail.com) 2058 if ($sex2 === 'M') { 2059 return I18N::translate('great ×%s grandson', I18N::number($up + 1)); 2060 } 2061 2062 if ($sex2 === 'F') { 2063 return I18N::translate('great ×%s granddaughter', I18N::number($up + 1)); 2064 } 2065 2066 return I18N::translate('great ×%s grandchild', I18N::number($up + 1)); 2067 2068 case 'zh-Hans': // Source: xmlf 2069 case 'zh-Hant': 2070 if ($sex2 === 'M') { 2071 return I18N::translate('great ×%s grandson', I18N::number($up)); 2072 } 2073 if ($sex2 === 'F') { 2074 return I18N::translate('great ×%s granddaughter', I18N::number($up)); 2075 } 2076 2077 return I18N::translate('great ×%s grandchild', I18N::number($up)); 2078 2079 case 'it': 2080 // Source: Michele Locati 2081 case 'es': 2082 // Source: Wes Groleau (adding doesn’t change behavior, but needs to be better researched) 2083 case 'en_AU': 2084 case 'en_GB': 2085 case 'en_US': 2086 default: 2087 if ($sex2 === 'M') { 2088 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 2089 return I18N::translate('great ×%s grandson', I18N::number($up - 2)); 2090 } 2091 2092 if ($sex2 === 'F') { 2093 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 2094 return I18N::translate('great ×%s granddaughter', I18N::number($up - 2)); 2095 } 2096 2097 // I18N: if you need a different number for %s, contact the developers, as a code-change is required 2098 return I18N::translate('great ×%s grandchild', I18N::number($up - 2)); 2099 } 2100 } 2101 } 2102 if (preg_match('/^((?:mot|fat|par)+)(?:bro|sis|sib)((?:son|dau|chi)+)$/', $path, $match)) { 2103 // cousins in English 2104 $ascent = $match[1]; 2105 $descent = $match[2]; 2106 $up = intdiv(strlen($ascent), 3); 2107 $down = intdiv(strlen($descent), 3); 2108 $cousin = min($up, $down); // Moved out of switch (en/default case) so that 2109 $removed = abs($down - $up); // Spanish (and other languages) can use it, too. 2110 2111 // Different languages have different rules for naming cousins. For example, 2112 // an English “second cousin once removed” is a Polish “cousin of 7th degree”. 2113 // 2114 // Need to find out which languages use which rules. 2115 switch (I18N::languageTag()) { 2116 case 'pl': // Source: Lukasz Wilenski 2117 return self::legacyCousinName($up + $down + 2, $sex2); 2118 case 'it': 2119 // Source: Michele Locati. See italian_cousins_names.zip 2120 // https://webtrees.net/forums/8-translation/1200-great-xn-grandparent?limit=6&start=6 2121 return self::legacyCousinName($up + $down - 3, $sex2); 2122 case 'es': 2123 if ($down === $up) { 2124 return self::legacyCousinName($cousin, $sex2); 2125 } 2126 2127 if ($down < $up) { 2128 return self::legacyCousinName2($cousin + 1, $sex2, $this->legacyNameAlgorithm('sib' . $descent)); 2129 } 2130 2131 if ($sex2 === 'M') { 2132 return self::legacyCousinName2($cousin + 1, $sex2, $this->legacyNameAlgorithm('bro' . $descent)); 2133 } 2134 2135 if ($sex2 === 'F') { 2136 return self::legacyCousinName2($cousin + 1, $sex2, $this->legacyNameAlgorithm('sis' . $descent)); 2137 } 2138 2139 return self::legacyCousinName2($cousin + 1, $sex2, $this->legacyNameAlgorithm('sib' . $descent)); 2140 2141 case 'en_AU': // See: https://en.wikipedia.org/wiki/File:CousinTree.svg 2142 case 'en_GB': 2143 case 'en_US': 2144 default: 2145 switch ($removed) { 2146 case 0: 2147 return self::legacyCousinName($cousin, $sex2); 2148 case 1: 2149 if ($up > $down) { 2150 /* I18N: %s=“fifth cousin”, etc. */ 2151 return I18N::translate('%s once removed ascending', self::legacyCousinName($cousin, $sex2)); 2152 } 2153 2154 /* I18N: %s=“fifth cousin”, etc. */ 2155 2156 return I18N::translate('%s once removed descending', self::legacyCousinName($cousin, $sex2)); 2157 case 2: 2158 if ($up > $down) { 2159 /* I18N: %s=“fifth cousin”, etc. */ 2160 return I18N::translate('%s twice removed ascending', self::legacyCousinName($cousin, $sex2)); 2161 } 2162 2163 /* I18N: %s=“fifth cousin”, etc. */ 2164 2165 return I18N::translate('%s twice removed descending', self::legacyCousinName($cousin, $sex2)); 2166 case 3: 2167 if ($up > $down) { 2168 /* I18N: %s=“fifth cousin”, etc. */ 2169 return I18N::translate('%s three times removed ascending', self::legacyCousinName($cousin, $sex2)); 2170 } 2171 2172 /* I18N: %s=“fifth cousin”, etc. */ 2173 2174 return I18N::translate('%s three times removed descending', self::legacyCousinName($cousin, $sex2)); 2175 default: 2176 if ($up > $down) { 2177 /* I18N: %1$s=“fifth cousin”, etc., %2$s>=4 */ 2178 return I18N::translate('%1$s %2$s times removed ascending', self::legacyCousinName($cousin, $sex2), I18N::number($removed)); 2179 } 2180 2181 /* I18N: %1$s=“fifth cousin”, etc., %2$s>=4 */ 2182 2183 return I18N::translate('%1$s %2$s times removed descending', self::legacyCousinName($cousin, $sex2), I18N::number($removed)); 2184 } 2185 } 2186 } 2187 2188 // Split the relationship into sub-relationships, e.g., third-cousin’s great-uncle. 2189 // Try splitting at every point, and choose the path with the shorted translated name. 2190 // But before starting to recursively go through all combinations, do a cache look-up 2191 2192 static $relationshipsCache; 2193 $relationshipsCache ??= []; 2194 if (array_key_exists($path, $relationshipsCache)) { 2195 return $relationshipsCache[$path]; 2196 } 2197 2198 $relationship = ''; 2199 $path1 = substr($path, 0, 3); 2200 $path2 = substr($path, 3); 2201 while ($path2 !== '') { 2202 // I18N: A complex relationship, such as “third-cousin’s great-uncle” 2203 $tmp = I18N::translate( 2204 '%1$s’s %2$s', 2205 $this->legacyNameAlgorithm($path1), 2206 $this->legacyNameAlgorithm($path2) 2207 ); 2208 if ($relationship === '' || strlen($tmp) < strlen($relationship)) { 2209 $relationship = $tmp; 2210 } 2211 $path1 .= substr($path2, 0, 3); 2212 $path2 = substr($path2, 3); 2213 } 2214 // and store the result in the cache 2215 $relationshipsCache[$path] = $relationship; 2216 2217 return $relationship; 2218 } 2219 2220 /** 2221 * Calculate the name of a cousin. 2222 * 2223 * @param int $n 2224 * @param string $sex 2225 * 2226 * @return string 2227 * 2228 * @deprecated 2229 */ 2230 private static function legacyCousinName(int $n, string $sex): string 2231 { 2232 if ($sex === 'M') { 2233 switch ($n) { 2234 case 1: 2235 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2236 return I18N::translateContext('MALE', 'first cousin'); 2237 case 2: 2238 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2239 return I18N::translateContext('MALE', 'second cousin'); 2240 case 3: 2241 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2242 return I18N::translateContext('MALE', 'third cousin'); 2243 case 4: 2244 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2245 return I18N::translateContext('MALE', 'fourth cousin'); 2246 case 5: 2247 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2248 return I18N::translateContext('MALE', 'fifth cousin'); 2249 case 6: 2250 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2251 return I18N::translateContext('MALE', 'sixth cousin'); 2252 case 7: 2253 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2254 return I18N::translateContext('MALE', 'seventh cousin'); 2255 case 8: 2256 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2257 return I18N::translateContext('MALE', 'eighth cousin'); 2258 case 9: 2259 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2260 return I18N::translateContext('MALE', 'ninth cousin'); 2261 case 10: 2262 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2263 return I18N::translateContext('MALE', 'tenth cousin'); 2264 case 11: 2265 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2266 return I18N::translateContext('MALE', 'eleventh cousin'); 2267 case 12: 2268 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2269 return I18N::translateContext('MALE', 'twelfth cousin'); 2270 case 13: 2271 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2272 return I18N::translateContext('MALE', 'thirteenth cousin'); 2273 case 14: 2274 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2275 return I18N::translateContext('MALE', 'fourteenth cousin'); 2276 case 15: 2277 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2278 return I18N::translateContext('MALE', 'fifteenth cousin'); 2279 default: 2280 /* I18N: Note that for Italian and Polish, “N’th cousins” are different from English “N’th cousins”, and the software has already generated the correct “N” for your language. You only need to translate - you do not need to convert. For other languages, if your cousin rules are different from English, please contact the developers. */ 2281 return I18N::translateContext('MALE', '%s × cousin', I18N::number($n)); 2282 } 2283 } 2284 2285 if ($sex === 'F') { 2286 switch ($n) { 2287 case 1: 2288 return I18N::translateContext('FEMALE', 'first cousin'); 2289 case 2: 2290 return I18N::translateContext('FEMALE', 'second cousin'); 2291 case 3: 2292 return I18N::translateContext('FEMALE', 'third cousin'); 2293 case 4: 2294 return I18N::translateContext('FEMALE', 'fourth cousin'); 2295 case 5: 2296 return I18N::translateContext('FEMALE', 'fifth cousin'); 2297 case 6: 2298 return I18N::translateContext('FEMALE', 'sixth cousin'); 2299 case 7: 2300 return I18N::translateContext('FEMALE', 'seventh cousin'); 2301 case 8: 2302 return I18N::translateContext('FEMALE', 'eighth cousin'); 2303 case 9: 2304 return I18N::translateContext('FEMALE', 'ninth cousin'); 2305 case 10: 2306 return I18N::translateContext('FEMALE', 'tenth cousin'); 2307 case 11: 2308 return I18N::translateContext('FEMALE', 'eleventh cousin'); 2309 case 12: 2310 return I18N::translateContext('FEMALE', 'twelfth cousin'); 2311 case 13: 2312 return I18N::translateContext('FEMALE', 'thirteenth cousin'); 2313 case 14: 2314 return I18N::translateContext('FEMALE', 'fourteenth cousin'); 2315 case 15: 2316 return I18N::translateContext('FEMALE', 'fifteenth cousin'); 2317 default: 2318 return I18N::translateContext('FEMALE', '%s × cousin', I18N::number($n)); 2319 } 2320 } 2321 2322 switch ($n) { 2323 case 1: 2324 return I18N::translate('first cousin'); 2325 case 2: 2326 return I18N::translate('second cousin'); 2327 case 3: 2328 return I18N::translate('third cousin'); 2329 case 4: 2330 return I18N::translate('fourth cousin'); 2331 case 5: 2332 return I18N::translate('fifth cousin'); 2333 case 6: 2334 return I18N::translate('sixth cousin'); 2335 case 7: 2336 return I18N::translate('seventh cousin'); 2337 case 8: 2338 return I18N::translate('eighth cousin'); 2339 case 9: 2340 return I18N::translate('ninth cousin'); 2341 case 10: 2342 return I18N::translate('tenth cousin'); 2343 case 11: 2344 return I18N::translate('eleventh cousin'); 2345 case 12: 2346 return I18N::translate('twelfth cousin'); 2347 case 13: 2348 return I18N::translate('thirteenth cousin'); 2349 case 14: 2350 return I18N::translate('fourteenth cousin'); 2351 case 15: 2352 return I18N::translate('fifteenth cousin'); 2353 default: 2354 return I18N::translate('%s × cousin', I18N::number($n)); 2355 } 2356 } 2357 2358 /** 2359 * A variation on cousin_name(), for constructs such as “sixth great-nephew” 2360 * Currently used only by Spanish relationship names. 2361 * 2362 * @param int $n 2363 * @param string $sex 2364 * @param string $relation 2365 * 2366 * @return string 2367 * 2368 * @deprecated 2369 */ 2370 private static function legacyCousinName2(int $n, string $sex, string $relation): string 2371 { 2372 if ($sex === 'M') { 2373 switch ($n) { 2374 case 1: 2375 /* I18N: A Spanish relationship name, such as third great-nephew */ 2376 return I18N::translateContext('MALE', 'first %s', $relation); 2377 case 2: 2378 /* I18N: A Spanish relationship name, such as third great-nephew */ 2379 return I18N::translateContext('MALE', 'second %s', $relation); 2380 case 3: 2381 /* I18N: A Spanish relationship name, such as third great-nephew */ 2382 return I18N::translateContext('MALE', 'third %s', $relation); 2383 case 4: 2384 /* I18N: A Spanish relationship name, such as third great-nephew */ 2385 return I18N::translateContext('MALE', 'fourth %s', $relation); 2386 case 5: 2387 /* I18N: A Spanish relationship name, such as third great-nephew */ 2388 return I18N::translateContext('MALE', 'fifth %s', $relation); 2389 default: 2390 /* I18N: A Spanish relationship name, such as third great-nephew */ 2391 return I18N::translateContext('MALE', '%1$s × %2$s', I18N::number($n), $relation); 2392 } 2393 } 2394 2395 if ($sex === 'F') { 2396 switch ($n) { 2397 case 1: 2398 /* I18N: A Spanish relationship name, such as third great-nephew */ 2399 return I18N::translateContext('FEMALE', 'first %s', $relation); 2400 case 2: 2401 /* I18N: A Spanish relationship name, such as third great-nephew */ 2402 return I18N::translateContext('FEMALE', 'second %s', $relation); 2403 case 3: 2404 /* I18N: A Spanish relationship name, such as third great-nephew */ 2405 return I18N::translateContext('FEMALE', 'third %s', $relation); 2406 case 4: 2407 /* I18N: A Spanish relationship name, such as third great-nephew */ 2408 return I18N::translateContext('FEMALE', 'fourth %s', $relation); 2409 case 5: 2410 /* I18N: A Spanish relationship name, such as third great-nephew */ 2411 return I18N::translateContext('FEMALE', 'fifth %s', $relation); 2412 default: 2413 /* I18N: A Spanish relationship name, such as third great-nephew */ 2414 return I18N::translateContext('FEMALE', '%1$s × %2$s', I18N::number($n), $relation); 2415 } 2416 } 2417 2418 switch ($n) { 2419 case 1: 2420 /* I18N: A Spanish relationship name, such as third great-nephew */ 2421 return I18N::translate('first %s', $relation); 2422 case 2: 2423 /* I18N: A Spanish relationship name, such as third great-nephew */ 2424 return I18N::translate('second %s', $relation); 2425 case 3: 2426 /* I18N: A Spanish relationship name, such as third great-nephew */ 2427 return I18N::translate('third %s', $relation); 2428 case 4: 2429 /* I18N: A Spanish relationship name, such as third great-nephew */ 2430 return I18N::translate('fourth %s', $relation); 2431 case 5: 2432 /* I18N: A Spanish relationship name, such as third great-nephew */ 2433 return I18N::translate('fifth %s', $relation); 2434 default: 2435 /* I18N: A Spanish relationship name, such as third great-nephew */ 2436 return I18N::translate('%1$s × %2$s', I18N::number($n), $relation); 2437 } 2438 } 2439} 2440