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