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