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