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