Completed
Push — develop ( 152113...fddfbb )
by Greg
12:05
created

Functions   D

Complexity

Total Complexity 768

Size/Duplication

Total Lines 2191
Duplicated Lines 36.33 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 796
loc 2191
rs 4.4102
wmc 768
lcom 1
cbo 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A fetchLatestVersion() 0 19 4
D fileUploadErrorText() 0 27 9
C getSubRecord() 0 30 7
A getCont() 0 16 4
C sortFacts() 0 46 7
A getCloseRelationshipName() 9 9 2
A getAssociateRelationshipName() 9 9 2
A reflexivePronoun() 0 10 3
D getRelationship() 70 124 24
B getRelationshipName() 0 29 2
D cousinName() 86 125 48
C cousinName2() 30 49 18
F getRelationshipNameFromPath() 592 1507 629
C getQueryUrl() 0 29 8
A isFileExternal() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Functions often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Functions, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * webtrees: online genealogy
4
 * Copyright (C) 2016 webtrees development team
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
 * GNU General Public License for more details.
13
 * You should have received a copy of the GNU General Public License
14
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15
 */
16
namespace Fisharebest\Webtrees\Functions;
17
18
use Fisharebest\Webtrees\Auth;
19
use Fisharebest\Webtrees\Database;
20
use Fisharebest\Webtrees\Fact;
21
use Fisharebest\Webtrees\File;
22
use Fisharebest\Webtrees\I18N;
23
use Fisharebest\Webtrees\Individual;
24
use Fisharebest\Webtrees\Site;
25
26
/**
27
 * Class Functions - common functions
28
 */
29
class Functions {
30
	/**
31
	 * Check with the webtrees.net server for the latest version of webtrees.
32
	 * Fetching the remote file can be slow, so check infrequently, and cache the result.
33
	 * Pass the current versions of webtrees, PHP and MySQL, as the response
34
	 * may be different for each. The server logs are used to generate
35
	 * installation statistics which can be found at http://svn.webtrees.net/statistics.html
36
	 *
37
	 * @return null|string
38
	 */
39
	public static function fetchLatestVersion() {
40
		$last_update_timestamp = Site::getPreference('LATEST_WT_VERSION_TIMESTAMP');
41
		if ($last_update_timestamp < WT_TIMESTAMP - 24 * 60 * 60) {
42
			$row                = Database::prepare("SHOW VARIABLES LIKE 'version'")->fetchOneRow();
43
			$params             = '?w=' . WT_VERSION . '&p=' . PHP_VERSION . '&m=' . $row->value . '&o=' . (DIRECTORY_SEPARATOR === '/' ? 'u' : 'w');
44
			$latest_version_txt = File::fetchUrl('https://dev.webtrees.net/build/latest-version.txt' . $params);
45
			if ($latest_version_txt) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $latest_version_txt of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
46
				Site::setPreference('LATEST_WT_VERSION', $latest_version_txt);
47
				Site::setPreference('LATEST_WT_VERSION_TIMESTAMP', WT_TIMESTAMP);
48
49
				return $latest_version_txt;
50
			} else {
51
				// Cannot connect to server - use cached version (if we have one)
52
				return Site::getPreference('LATEST_WT_VERSION');
53
			}
54
		} else {
55
			return Site::getPreference('LATEST_WT_VERSION');
56
		}
57
	}
58
59
	/**
60
	 * Convert a file upload PHP error code into user-friendly text.
61
	 *
62
	 * @param int $error_code
63
	 *
64
	 * @return string
65
	 */
66
	public static function fileUploadErrorText($error_code) {
67
		switch ($error_code) {
68
		case UPLOAD_ERR_OK:
69
			return I18N::translate('File successfully uploaded');
70
		case UPLOAD_ERR_INI_SIZE:
71
		case UPLOAD_ERR_FORM_SIZE:
72
			// I18N: PHP internal error message - php.net/manual/en/features.file-upload.errors.php
73
			return I18N::translate('The uploaded file exceeds the allowed size.');
74
		case UPLOAD_ERR_PARTIAL:
75
			// I18N: PHP internal error message - php.net/manual/en/features.file-upload.errors.php
76
			return I18N::translate('The file was only partially uploaded. Please try again.');
77
		case UPLOAD_ERR_NO_FILE:
78
			// I18N: PHP internal error message - php.net/manual/en/features.file-upload.errors.php
79
			return I18N::translate('No file was received. Please try again.');
80
		case UPLOAD_ERR_NO_TMP_DIR:
81
			// I18N: PHP internal error message - php.net/manual/en/features.file-upload.errors.php
82
			return I18N::translate('The PHP temporary folder is missing.');
83
		case UPLOAD_ERR_CANT_WRITE:
84
			// I18N: PHP internal error message - php.net/manual/en/features.file-upload.errors.php
85
			return I18N::translate('PHP failed to write to disk.');
86
		case UPLOAD_ERR_EXTENSION:
87
			// I18N: PHP internal error message - php.net/manual/en/features.file-upload.errors.php
88
			return I18N::translate('PHP blocked the file because of its extension.');
89
		default:
90
			return 'Error: ' . $error_code;
91
		}
92
	}
93
94
	/**
95
	 * get a gedcom subrecord
96
	 *
97
	 * searches a gedcom record and returns a subrecord of it. A subrecord is defined starting at a
98
	 * line with level N and all subsequent lines greater than N until the next N level is reached.
99
	 * For example, the following is a BIRT subrecord:
100
	 * <code>1 BIRT
101
	 * 2 DATE 1 JAN 1900
102
	 * 2 PLAC Phoenix, Maricopa, Arizona</code>
103
	 * The following example is the DATE subrecord of the above BIRT subrecord:
104
	 * <code>2 DATE 1 JAN 1900</code>
105
	 *
106
	 * @param int $level the N level of the subrecord to get
107
	 * @param string $tag a gedcom tag or string to search for in the record (ie 1 BIRT or 2 DATE)
108
	 * @param string $gedrec the parent gedcom record to search in
109
	 * @param int $num this allows you to specify which matching <var>$tag</var> to get. Oftentimes a
110
	 *                        gedcom record will have more that 1 of the same type of subrecord. An individual may have
111
	 *                        multiple events for example. Passing $num=1 would get the first 1. Passing $num=2 would get the
112
	 *                        second one, etc.
113
	 *
114
	 * @return string the subrecord that was found or an empty string "" if not found.
115
	 */
116
	public static function getSubRecord($level, $tag, $gedrec, $num = 1) {
117
		if (empty($gedrec)) {
118
			return '';
119
		}
120
		// -- adding \n before and after gedrec
121
		$gedrec       = "\n" . $gedrec . "\n";
122
		$tag          = trim($tag);
123
		$searchTarget = "~[\n]" . $tag . "[\s]~";
124
		$ct           = preg_match_all($searchTarget, $gedrec, $match, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
125
		if ($ct == 0) {
126
			return '';
127
		}
128
		if ($ct < $num) {
129
			return '';
130
		}
131
		$pos1 = $match[$num - 1][0][1];
132
		$pos2 = strpos($gedrec, "\n$level", $pos1 + 1);
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $level instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
133
		if (!$pos2) {
134
			$pos2 = strpos($gedrec, "\n1", $pos1 + 1);
135
		}
136
		if (!$pos2) {
137
			$pos2 = strpos($gedrec, "\nWT_", $pos1 + 1); // WT_SPOUSE, WT_FAMILY_ID ...
138
		}
139
		if (!$pos2) {
140
			return ltrim(substr($gedrec, $pos1));
141
		}
142
		$subrec = substr($gedrec, $pos1, $pos2 - $pos1);
143
144
		return ltrim($subrec);
145
	}
146
147
	/**
148
	 * get CONT lines
149
	 *
150
	 * get the N+1 CONT or CONC lines of a gedcom subrecord
151
	 *
152
	 * @param int $nlevel the level of the CONT lines to get
153
	 * @param string $nrec the gedcom subrecord to search in
154
	 *
155
	 * @return string a string with all CONT lines merged
156
	 */
157
	public static function getCont($nlevel, $nrec) {
158
		$text = '';
159
160
		$subrecords = explode("\n", $nrec);
161
		foreach ($subrecords as $thisSubrecord) {
162
			if (substr($thisSubrecord, 0, 2) !== $nlevel . ' ') {
163
				continue;
164
			}
165
			$subrecordType = substr($thisSubrecord, 2, 4);
166
			if ($subrecordType === 'CONT') {
167
				$text .= "\n" . substr($thisSubrecord, 7);
168
			}
169
		}
170
171
		return $text;
172
	}
173
174
	/**
175
	 * A multi-key sort
176
	 * 1. First divide the facts into two arrays one set with dates and one set without dates
177
	 * 2. Sort each of the two new arrays, the date using the compare date function, the non-dated
178
	 * using the compare type function
179
	 * 3. Then merge the arrays back into the original array using the compare type function
180
	 *
181
	 * @param Fact[] $arr
182
	 */
183
	public static function sortFacts(&$arr) {
184
		$dated    = array();
185
		$nondated = array();
186
		//-- split the array into dated and non-dated arrays
187
		$order = 0;
188
		foreach ($arr as $event) {
189
			$event->sortOrder = $order;
190
			$order++;
191
			if ($event->getDate()->isOK()) {
192
				$dated[] = $event;
193
			} else {
194
				$nondated[] = $event;
195
			}
196
		}
197
198
		//-- sort each type of array
199
		usort($dated, '\Fisharebest\Webtrees\Fact::compareDate');
200
		usort($nondated, '\Fisharebest\Webtrees\Fact::compareType');
201
202
		//-- merge the arrays back together comparing by Facts
203
		$dc = count($dated);
204
		$nc = count($nondated);
205
		$i  = 0;
206
		$j  = 0;
207
		$k  = 0;
208
		// while there is anything in the dated array continue merging
209
		while ($i < $dc) {
210
			// compare each fact by type to merge them in order
211
			if ($j < $nc && Fact::compareType($dated[$i], $nondated[$j]) > 0) {
212
				$arr[$k] = $nondated[$j];
213
				$j++;
214
			} else {
215
				$arr[$k] = $dated[$i];
216
				$i++;
217
			}
218
			$k++;
219
		}
220
221
		// get anything that might be left in the nondated array
222
		while ($j < $nc) {
223
			$arr[$k] = $nondated[$j];
224
			$j++;
225
			$k++;
226
		}
227
228
	}
229
230
	/**
231
	 * For close family relationships, such as the families tab and the family navigator
232
	 * Display a tick if both individuals are the same.
233
	 *
234
	 * @param Individual $individual1
235
	 * @param Individual $individual2
236
	 *
237
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
238
	 */
239 View Code Duplication
	public static function getCloseRelationshipName(Individual $individual1, Individual $individual2) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
		if ($individual1 === $individual2) {
241
			$label = '<i class="icon-selected"></i> ' . self::reflexivePronoun($individual1);
242
		} else {
243
			$label = self::getRelationshipName(self::getRelationship($individual1, $individual2));
0 ignored issues
show
Documentation introduced by
self::getRelationship($individual1, $individual2) is of type false|array<string,array...ebtrees\\Individual>"}>, but the function expects a array<integer,array<integer,*>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
244
		}
245
246
		return $label;
247
	}
248
249
	/**
250
	 * For facts on the individual/family pages.
251
	 *
252
	 * @param Individual $individual1
253
	 * @param Individual $individual2
254
	 *
255
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
256
	 */
257 View Code Duplication
	public static function getAssociateRelationshipName(Individual $individual1, Individual $individual2) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
258
		if ($individual1 === $individual2) {
259
			$label = self::reflexivePronoun($individual1);
260
		} else {
261
			$label = self::getRelationshipName(self::getRelationship($individual1, $individual2));
0 ignored issues
show
Documentation introduced by
self::getRelationship($individual1, $individual2) is of type false|array<string,array...ebtrees\\Individual>"}>, but the function expects a array<integer,array<integer,*>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
262
		}
263
264
		return $label;
265
	}
266
267
	/**
268
	 * Generate a reflexive pronoun for an individual
269
	 *
270
	 * @param Individual $individual
271
	 *
272
	 * @return string
273
	 */
274
	private static function reflexivePronoun(Individual $individual) {
275
		switch ($individual->getSex()) {
276
		case 'M':
277
			return /* I18N: reflexive pronoun */ I18N::translate('himself');
278
		case 'F':
279
			return /* I18N: reflexive pronoun */ I18N::translate('herself');
280
		default:
281
			return /* I18N: reflexive pronoun - gender neutral version of himself/herself */ I18N::translate('themself');
282
		}
283
	}
284
285
	/**
286
	 * Get relationship between two individuals in the gedcom
287
	 *
288
	 * @param Individual $person1 The person to compute the relationship from
289
	 * @param Individual $person2 The person to compute the relatiohip to
290
	 * @param int $maxlength The maximum length of path
291
	 *
292
	 * @return array|bool An array of nodes on the relationship path, or false if no path found
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use false|array<string,Indiv...er|Individual|string[]>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
293
	 */
294
	public static function getRelationship(Individual $person1, Individual $person2, $maxlength = 4) {
295
		if ($person1 === $person2) {
296
			return false;
297
		}
298
299
		$spouse_codes  = array('M' => 'hus', 'F' => 'wif', 'U' => 'spo');
300
		$parent_codes  = array('M' => 'fat', 'F' => 'mot', 'U' => 'par');
301
		$child_codes   = array('M' => 'son', 'F' => 'dau', 'U' => 'chi');
302
		$sibling_codes = array('M' => 'bro', 'F' => 'sis', 'U' => 'sib');
303
304
		//-- current path nodes
305
		$p1nodes = array();
306
		//-- ids visited
307
		$visited = array();
308
309
		//-- set up first node for person1
310
		$node1 = array(
311
			'path'      => array($person1),
312
			'length'    => 0,
313
			'indi'      => $person1,
314
			'relations' => array('self'),
315
		);
316
		$p1nodes[] = $node1;
317
318
		$visited[$person1->getXref()] = true;
319
320
		$found = false;
321
		while (!$found) {
322
			//-- search the node list for the shortest path length
323
			$shortest = -1;
324
			foreach ($p1nodes as $index => $node) {
325
				if ($shortest == -1) {
326
					$shortest = $index;
327
				} else {
328
					$node1 = $p1nodes[$shortest];
329
					if ($node1['length'] > $node['length']) {
330
						$shortest = $index;
331
					}
332
				}
333
			}
334
			if ($shortest === -1) {
335
				return false;
336
			}
337
			$node = $p1nodes[$shortest];
338
			if ($maxlength == 0 || count($node['path']) <= $maxlength) {
339
				$indi = $node['indi'];
340
				//-- check all parents and siblings of this node
341 View Code Duplication
				foreach ($indi->getChildFamilies(Auth::PRIV_HIDE) as $family) {
342
					$visited[$family->getXref()] = true;
343
					foreach ($family->getSpouses(Auth::PRIV_HIDE) as $spouse) {
344
						if (!isset($visited[$spouse->getXref()])) {
345
							$node1 = $node;
346
							$node1['length']++;
347
							$node1['path'][]      = $spouse;
348
							$node1['indi']        = $spouse;
349
							$node1['relations'][] = $parent_codes[$spouse->getSex()];
350
							$p1nodes[]            = $node1;
351
							if ($spouse === $person2) {
352
								$found   = true;
353
								$resnode = $node1;
354
							} else {
355
								$visited[$spouse->getXref()] = true;
356
							}
357
						}
358
					}
359
					foreach ($family->getChildren(Auth::PRIV_HIDE) as $child) {
360
						if (!isset($visited[$child->getXref()])) {
361
							$node1 = $node;
362
							$node1['length']++;
363
							$node1['path'][]      = $child;
364
							$node1['indi']        = $child;
365
							$node1['relations'][] = $sibling_codes[$child->getSex()];
366
							$p1nodes[]            = $node1;
367
							if ($child === $person2) {
368
								$found   = true;
369
								$resnode = $node1;
370
							} else {
371
								$visited[$child->getXref()] = true;
372
							}
373
						}
374
					}
375
				}
376
				//-- check all spouses and children of this node
377 View Code Duplication
				foreach ($indi->getSpouseFamilies(Auth::PRIV_HIDE) as $family) {
378
					$visited[$family->getXref()] = true;
379
					foreach ($family->getSpouses(Auth::PRIV_HIDE) as $spouse) {
380
						if (!in_array($spouse->getXref(), $node1) || !isset($visited[$spouse->getXref()])) {
381
							$node1 = $node;
382
							$node1['length']++;
383
							$node1['path'][]      = $spouse;
384
							$node1['indi']        = $spouse;
385
							$node1['relations'][] = $spouse_codes[$spouse->getSex()];
386
							$p1nodes[]            = $node1;
387
							if ($spouse === $person2) {
388
								$found   = true;
389
								$resnode = $node1;
390
							} else {
391
								$visited[$spouse->getXref()] = true;
392
							}
393
						}
394
					}
395
					foreach ($family->getChildren(Auth::PRIV_HIDE) as $child) {
396
						if (!isset($visited[$child->getXref()])) {
397
							$node1 = $node;
398
							$node1['length']++;
399
							$node1['path'][]      = $child;
400
							$node1['indi']        = $child;
401
							$node1['relations'][] = $child_codes[$child->getSex()];
402
							$p1nodes[]            = $node1;
403
							if ($child === $person2) {
404
								$found   = true;
405
								$resnode = $node1;
406
							} else {
407
								$visited[$child->getXref()] = true;
408
							}
409
						}
410
					}
411
				}
412
			}
413
			unset($p1nodes[$shortest]);
414
		}
415
416
		return $resnode;
0 ignored issues
show
Bug introduced by
The variable $resnode does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
417
	}
418
419
	/**
420
	 * Convert the result of get_relationship() into a relationship name.
421
	 *
422
	 * @param mixed[][] $nodes
423
	 *
424
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
425
	 */
426
	public static function getRelationshipName($nodes) {
427
		if (!is_array($nodes)) {
428
			return '';
429
		}
430
		$person1 = $nodes['path'][0];
431
		$person2 = $nodes['path'][count($nodes['path']) - 1];
432
		$path    = array_slice($nodes['relations'], 1);
433
		// Look for paths with *specific* names first.
434
		// Note that every combination must be listed separately, as the same English
435
		// name can be used for many different relationships. e.g.
436
		// brother’s wife & husband’s sister = sister-in-law.
437
		//
438
		// $path is an array of the 12 possible gedcom family relationships:
439
		// mother/father/parent
440
		// brother/sister/sibling
441
		// husband/wife/spouse
442
		// son/daughter/child
443
		//
444
		// This is always the shortest path, so “father, daughter” is “half-sister”, not “sister”.
445
		//
446
		// This is very repetitive in English, but necessary in order to handle the
447
		// complexities of other languages.
448
449
		return self::getRelationshipNameFromPath(
450
			implode('', $path),
451
			$person1,
452
			$person2
453
		);
454
	}
455
456
	/**
457
	 * Calculate the name of a cousin.
458
	 *
459
	 * @param int $n
460
	 * @param string $sex
461
	 *
462
	 * @return string
463
	 */
464
	public static function cousinName($n, $sex) {
465
		switch ($sex) {
466 View Code Duplication
		case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
467
			switch ($n) {
468
			case  1:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
469
			/* 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. */
470
			return I18N::translateContext('MALE', 'first cousin');
471
			case  2:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
472
			/* 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. */
473
			return I18N::translateContext('MALE', 'second cousin');
474
			case  3:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
475
			/* 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. */
476
			return I18N::translateContext('MALE', 'third cousin');
477
			case  4:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
478
			/* 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. */
479
			return I18N::translateContext('MALE', 'fourth cousin');
480
			case  5:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
481
			/* 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. */
482
			return I18N::translateContext('MALE', 'fifth cousin');
483
			case  6:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
484
			/* 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. */
485
			return I18N::translateContext('MALE', 'sixth cousin');
486
			case  7:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
487
			/* 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. */
488
			return I18N::translateContext('MALE', 'seventh cousin');
489
			case  8:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
490
			/* 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. */
491
			return I18N::translateContext('MALE', 'eighth cousin');
492
			case  9:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
493
			/* 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. */
494
			return I18N::translateContext('MALE', 'ninth cousin');
495
			case 10:
496
			/* 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. */
497
			return I18N::translateContext('MALE', 'tenth cousin');
498
			case 11:
499
			/* 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. */
500
			return I18N::translateContext('MALE', 'eleventh cousin');
501
			case 12:
502
			/* 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. */
503
			return I18N::translateContext('MALE', 'twelfth cousin');
504
			case 13:
505
			/* 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. */
506
			return I18N::translateContext('MALE', 'thirteenth cousin');
507
			case 14:
508
			/* 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. */
509
			return I18N::translateContext('MALE', 'fourteenth cousin');
510
			case 15:
511
			/* 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. */
512
			return I18N::translateContext('MALE', 'fifteenth cousin');
513
			default:
514
			/* 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. */
515
			return I18N::translateContext('MALE', '%s × cousin', I18N::number($n));
516
			}
517 View Code Duplication
		case 'F':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
518
			switch ($n) {
519
			case  1:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
520
			return I18N::translateContext('FEMALE', 'first cousin');
521
			case  2:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
522
			return I18N::translateContext('FEMALE', 'second cousin');
523
			case  3:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
524
			return I18N::translateContext('FEMALE', 'third cousin');
525
			case  4:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
526
			return I18N::translateContext('FEMALE', 'fourth cousin');
527
			case  5:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
528
			return I18N::translateContext('FEMALE', 'fifth cousin');
529
			case  6:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
530
			return I18N::translateContext('FEMALE', 'sixth cousin');
531
			case  7:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
532
			return I18N::translateContext('FEMALE', 'seventh cousin');
533
			case  8:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
534
			return I18N::translateContext('FEMALE', 'eighth cousin');
535
			case  9:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
536
			return I18N::translateContext('FEMALE', 'ninth cousin');
537
			case 10:
538
			return I18N::translateContext('FEMALE', 'tenth cousin');
539
			case 11:
540
			return I18N::translateContext('FEMALE', 'eleventh cousin');
541
			case 12:
542
			return I18N::translateContext('FEMALE', 'twelfth cousin');
543
			case 13:
544
			return I18N::translateContext('FEMALE', 'thirteenth cousin');
545
			case 14:
546
			return I18N::translateContext('FEMALE', 'fourteenth cousin');
547
			case 15:
548
			return I18N::translateContext('FEMALE', 'fifteenth cousin');
549
			default:
550
			return I18N::translateContext('FEMALE', '%s × cousin', I18N::number($n));
551
			}
552
		default:
553
			switch ($n) {
554
			case  1:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
555
			return I18N::translate('first cousin');
556
			case  2:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
557
			return I18N::translate('second cousin');
558
			case  3:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
559
			return I18N::translate('third cousin');
560
			case  4:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
561
			return I18N::translate('fourth cousin');
562
			case  5:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
563
			return I18N::translate('fifth cousin');
564
			case  6:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
565
			return I18N::translate('sixth cousin');
566
			case  7:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
567
			return I18N::translate('seventh cousin');
568
			case  8:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
569
			return I18N::translate('eighth cousin');
570
			case  9:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
571
			return I18N::translate('ninth cousin');
572
			case 10:
573
			return I18N::translate('tenth cousin');
574
			case 11:
575
			return I18N::translate('eleventh cousin');
576
			case 12:
577
			return I18N::translate('twelfth cousin');
578
			case 13:
579
			return I18N::translate('thirteenth cousin');
580
			case 14:
581
			return I18N::translate('fourteenth cousin');
582
			case 15:
583
			return I18N::translate('fifteenth cousin');
584
			default:
585
			return I18N::translate('%s × cousin', I18N::number($n));
586
			}
587
		}
588
	}
589
590
	/**
591
	 * A variation on cousin_name(), for constructs such as “sixth great-nephew”
592
	 * Currently used only by Spanish relationship names.
593
	 *
594
	 * @param int $n
595
	 * @param string $sex
596
	 * @param string $relation
597
	 *
598
	 * @return string
599
	 */
600
	public static function cousinName2($n, $sex, $relation) {
601
		switch ($sex) {
602 View Code Duplication
		case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
603
			switch ($n) {
604
			case  1:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
605
				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('MALE', 'first %s', $relation);
606
			case  2:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
607
				return I18N::translateContext('MALE', 'second %s', $relation);
608
			case  3:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
609
				return I18N::translateContext('MALE', 'third %s', $relation);
610
			case  4:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
611
				return I18N::translateContext('MALE', 'fourth %s', $relation);
612
			case  5:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
613
				return I18N::translateContext('MALE', 'fifth %s', $relation);
614
			default:
615
				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('MALE', '%1$s × %2$s', I18N::number($n), $relation);
616
			}
617 View Code Duplication
		case 'F':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
618
			switch ($n) {
619
			case  1:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
620
				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('FEMALE', 'first %s', $relation);
621
			case  2:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
622
				return I18N::translateContext('FEMALE', 'second %s', $relation);
623
			case  3:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
624
				return I18N::translateContext('FEMALE', 'third %s', $relation);
625
			case  4:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
626
				return I18N::translateContext('FEMALE', 'fourth %s', $relation);
627
			case  5:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
628
				return I18N::translateContext('FEMALE', 'fifth %s', $relation);
629
			default: // I18N: A Spanish relationship name, such as third great-nephew
630
				return I18N::translateContext('FEMALE', '%1$s × %2$s', I18N::number($n), $relation);
631
			}
632
		default:
633
			switch ($n) {
634
			case  1:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
635
				return /* I18N: A Spanish relationship name, such as first great-nephew */ I18N::translate('first %s', $relation);
636
			case  2:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
637
				return /* I18N: A Spanish relationship name, such as second great-nephew */ I18N::translate('second %s', $relation);
638
			case  3:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
639
				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translate('third %s', $relation);
640
			case  4:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
641
				return /* I18N: A Spanish relationship name, such as fourth great-nephew */ I18N::translate('fourth %s', $relation);
642
			case  5:
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
643
				return /* I18N: A Spanish relationship name, such as fifth great-nephew */ I18N::translate('fifth %s', $relation);
644
			default:
645
				return /* I18N: A Spanish relationship name, such as 7th great-nephew */ I18N::translate('%1$s × %2$s', I18N::number($n), $relation);
646
			}
647
		}
648
	}
649
650
	/** @var string[] Cache for generic relationships (key stores the path, and value represents the relationship name) */
651
	protected static $relationshipsCache = array();
652
653
	/**
654
	 * Convert a relationship path into a relationship name.
655
	 *
656
	 * @param string $path
657
	 * @param Individual $person1
0 ignored issues
show
Documentation introduced by
Should the type for parameter $person1 not be null|Individual?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
658
	 * @param Individual $person2
0 ignored issues
show
Documentation introduced by
Should the type for parameter $person2 not be null|Individual?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
659
	 *
660
	 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
661
	 */
662
	public static function getRelationshipNameFromPath($path, Individual $person1 = null, Individual $person2 = null) {
663
		if (!preg_match('/^(mot|fat|par|hus|wif|spo|son|dau|chi|bro|sis|sib)*$/', $path)) {
664
			// TODO: Update all the “3 RELA ” values in class_person
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
665
			return '<span class="error">' . $path . '</span>';
666
		}
667
		// The path does not include the starting person. In some languages, the
668
		// translation for a man’s (relative) is different from a woman’s (relative),
669
		// due to inflection.
670
		$sex1 = $person1 ? $person1->getSex() : 'U';
671
672
		// The sex of the last person in the relationship determines the name in
673
		// many cases. e.g. great-aunt / great-uncle
674
		if (preg_match('/(fat|hus|son|bro)$/', $path)) {
675
			$sex2 = 'M';
676
		} elseif (preg_match('/(mot|wif|dau|sis)$/', $path)) {
677
			$sex2 = 'F';
678
		} else {
679
			$sex2 = 'U';
680
		}
681
682
		switch ($path) {
683
		case '':
684
			return I18N::translate('self');
685
		//  Level One relationships
686
		case 'mot':
687
			return I18N::translate('mother');
688
		case 'fat':
689
			return I18N::translate('father');
690
		case 'par':
691
			return I18N::translate('parent');
692 View Code Duplication
		case 'hus':
693
			if ($person1 && $person2) {
694
				foreach ($person1->getSpouseFamilies() as $family) {
695
					if ($person2 === $family->getSpouse($person1)) {
696
						if ($family->getFacts('_NMR')) {
697
							if ($family->getFacts(WT_EVENTS_DIV)) {
698
								return I18N::translateContext('MALE', 'ex-partner');
699
							} else {
700
								return I18N::translateContext('MALE', 'partner');
701
							}
702
						} elseif ($family->getFacts(WT_EVENTS_DIV)) {
703
							return I18N::translate('ex-husband');
704
						}
705
					}
706
				}
707
			}
708
709
			return I18N::translate('husband');
710 View Code Duplication
		case 'wif':
711
			if ($person1 && $person2) {
712
				foreach ($person1->getSpouseFamilies() as $family) {
713
					if ($person2 === $family->getSpouse($person1)) {
714
						if ($family->getFacts('_NMR')) {
715
							if ($family->getFacts(WT_EVENTS_DIV)) {
716
								return I18N::translateContext('FEMALE', 'ex-partner');
717
							} else {
718
								return I18N::translateContext('FEMALE', 'partner');
719
							}
720
						} elseif ($family->getFacts(WT_EVENTS_DIV)) {
721
							return I18N::translate('ex-wife');
722
						}
723
					}
724
				}
725
			}
726
727
			return I18N::translate('wife');
728 View Code Duplication
		case 'spo':
729
			if ($person1 && $person2) {
730
				foreach ($person1->getSpouseFamilies() as $family) {
731
					if ($person2 === $family->getSpouse($person1)) {
732
						if ($family->getFacts('_NMR')) {
733
							if ($family->getFacts(WT_EVENTS_DIV)) {
734
								return I18N::translate('ex-partner');
735
							} else {
736
								return I18N::translate('partner');
737
							}
738
						} elseif ($family->getFacts(WT_EVENTS_DIV)) {
739
							return I18N::translate('ex-spouse');
740
						}
741
					}
742
				}
743
			}
744
745
			return I18N::translate('spouse');
746
		case 'son':
747
			return I18N::translate('son');
748
		case 'dau':
749
			return I18N::translate('daughter');
750
		case 'chi':
751
			return I18N::translate('child');
752 View Code Duplication
		case 'bro':
753
			if ($person1 && $person2) {
754
				$dob1 = $person1->getBirthDate();
755
				$dob2 = $person2->getBirthDate();
756
				if ($dob1->isOK() && $dob2->isOK()) {
757
					if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && !$dob1->minimumDate()->d !== 0 && !$dob2->minimumDate()->d !== 0) {
758
						// Exclude BEF, AFT, etc.
759
						return I18N::translate('twin brother');
760
					} elseif ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) {
761
						return I18N::translate('younger brother');
762
					} elseif ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) {
763
						return I18N::translate('elder brother');
764
					}
765
				}
766
			}
767
768
			return I18N::translate('brother');
769 View Code Duplication
		case 'sis':
770
			if ($person1 && $person2) {
771
				$dob1 = $person1->getBirthDate();
772
				$dob2 = $person2->getBirthDate();
773
				if ($dob1->isOK() && $dob2->isOK()) {
774
					if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && !$dob1->minimumDate()->d !== 0 && !$dob2->minimumDate()->d !== 0) {
775
						// Exclude BEF, AFT, etc.
776
						return I18N::translate('twin sister');
777
					} elseif ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) {
778
						return I18N::translate('younger sister');
779
					} elseif ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) {
780
						return I18N::translate('elder sister');
781
					}
782
				}
783
			}
784
785
			return I18N::translate('sister');
786 View Code Duplication
		case 'sib':
787
			if ($person1 && $person2) {
788
				$dob1 = $person1->getBirthDate();
789
				$dob2 = $person2->getBirthDate();
790
				if ($dob1->isOK() && $dob2->isOK()) {
791
					if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && !$dob1->minimumDate()->d !== 0 && !$dob2->minimumDate()->d !== 0) {
792
						// Exclude BEF, AFT, etc.
793
						return I18N::translate('twin sibling');
794
					} elseif ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) {
795
						return I18N::translate('younger sibling');
796
					} elseif ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) {
797
						return I18N::translate('elder sibling');
798
					}
799
				}
800
			}
801
802
			return I18N::translate('sibling');
803
804
		// Level Two relationships
805
		case 'brochi':
806
			return I18N::translateContext('brother’s child', 'nephew/niece');
807
		case 'brodau':
808
			return I18N::translateContext('brother’s daughter', 'niece');
809
		case 'broson':
810
			return I18N::translateContext('brother’s son', 'nephew');
811
		case 'browif':
812
			return I18N::translateContext('brother’s wife', 'sister-in-law');
813
		case 'chichi':
814
			return I18N::translateContext('child’s child', 'grandchild');
815
		case 'chidau':
816
			return I18N::translateContext('child’s daughter', 'granddaughter');
817
		case 'chihus':
818
			return I18N::translateContext('child’s husband', 'son-in-law');
819
		case 'chison':
820
			return I18N::translateContext('child’s son', 'grandson');
821
		case 'chispo':
822
			return I18N::translateContext('child’s spouse', 'son/daughter-in-law');
823
		case 'chiwif':
824
			return I18N::translateContext('child’s wife', 'daughter-in-law');
825
		case 'dauchi':
826
			return I18N::translateContext('daughter’s child', 'grandchild');
827
		case 'daudau':
828
			return I18N::translateContext('daughter’s daughter', 'granddaughter');
829
		case 'dauhus':
830
			return I18N::translateContext('daughter’s husband', 'son-in-law');
831
		case 'dauson':
832
			return I18N::translateContext('daughter’s son', 'grandson');
833
		case 'fatbro':
834
			return I18N::translateContext('father’s brother', 'uncle');
835
		case 'fatchi':
836
			return I18N::translateContext('father’s child', 'half-sibling');
837
		case 'fatdau':
838
			return I18N::translateContext('father’s daughter', 'half-sister');
839
		case 'fatfat':
840
			return I18N::translateContext('father’s father', 'paternal grandfather');
841
		case 'fatmot':
842
			return I18N::translateContext('father’s mother', 'paternal grandmother');
843
		case 'fatpar':
844
			return I18N::translateContext('father’s parent', 'paternal grandparent');
845
		case 'fatsib':
846
			return I18N::translateContext('father’s sibling', 'aunt/uncle');
847
		case 'fatsis':
848
			return I18N::translateContext('father’s sister', 'aunt');
849
		case 'fatson':
850
			return I18N::translateContext('father’s son', 'half-brother');
851
		case 'fatwif':
852
			return I18N::translateContext('father’s wife', 'step-mother');
853
		case 'husbro':
854
			return I18N::translateContext('husband’s brother', 'brother-in-law');
855
		case 'huschi':
856
			return I18N::translateContext('husband’s child', 'step-child');
857
		case 'husdau':
858
			return I18N::translateContext('husband’s daughter', 'step-daughter');
859
		case 'husfat':
860
			return I18N::translateContext('husband’s father', 'father-in-law');
861
		case 'husmot':
862
			return I18N::translateContext('husband’s mother', 'mother-in-law');
863
		case 'hussib':
864
			return I18N::translateContext('husband’s sibling', 'brother/sister-in-law');
865
		case 'hussis':
866
			return I18N::translateContext('husband’s sister', 'sister-in-law');
867
		case 'husson':
868
			return I18N::translateContext('husband’s son', 'step-son');
869
		case 'motbro':
870
			return I18N::translateContext('mother’s brother', 'uncle');
871
		case 'motchi':
872
			return I18N::translateContext('mother’s child', 'half-sibling');
873
		case 'motdau':
874
			return I18N::translateContext('mother’s daughter', 'half-sister');
875
		case 'motfat':
876
			return I18N::translateContext('mother’s father', 'maternal grandfather');
877
		case 'mothus':
878
			return I18N::translateContext('mother’s husband', 'step-father');
879
		case 'motmot':
880
			return I18N::translateContext('mother’s mother', 'maternal grandmother');
881
		case 'motpar':
882
			return I18N::translateContext('mother’s parent', 'maternal grandparent');
883
		case 'motsib':
884
			return I18N::translateContext('mother’s sibling', 'aunt/uncle');
885
		case 'motsis':
886
			return I18N::translateContext('mother’s sister', 'aunt');
887
		case 'motson':
888
			return I18N::translateContext('mother’s son', 'half-brother');
889
		case 'parbro':
890
			return I18N::translateContext('parent’s brother', 'uncle');
891
		case 'parchi':
892
			return I18N::translateContext('parent’s child', 'half-sibling');
893
		case 'pardau':
894
			return I18N::translateContext('parent’s daughter', 'half-sister');
895
		case 'parfat':
896
			return I18N::translateContext('parent’s father', 'grandfather');
897
		case 'parmot':
898
			return I18N::translateContext('parent’s mother', 'grandmother');
899
		case 'parpar':
900
			return I18N::translateContext('parent’s parent', 'grandparent');
901
		case 'parsib':
902
			return I18N::translateContext('parent’s sibling', 'aunt/uncle');
903
		case 'parsis':
904
			return I18N::translateContext('parent’s sister', 'aunt');
905
		case 'parson':
906
			return I18N::translateContext('parent’s son', 'half-brother');
907
		case 'parspo':
908
			return I18N::translateContext('parent’s spouse', 'step-parent');
909
		case 'sibchi':
910
			return I18N::translateContext('sibling’s child', 'nephew/niece');
911
		case 'sibdau':
912
			return I18N::translateContext('sibling’s daughter', 'niece');
913
		case 'sibson':
914
			return I18N::translateContext('sibling’s son', 'nephew');
915
		case 'sibspo':
916
			return I18N::translateContext('sibling’s spouse', 'brother/sister-in-law');
917
		case 'sischi':
918
			return I18N::translateContext('sister’s child', 'nephew/niece');
919
		case 'sisdau':
920
			return I18N::translateContext('sister’s daughter', 'niece');
921
		case 'sishus':
922
			return I18N::translateContext('sister’s husband', 'brother-in-law');
923
		case 'sisson':
924
			return I18N::translateContext('sister’s son', 'nephew');
925
		case 'sonchi':
926
			return I18N::translateContext('son’s child', 'grandchild');
927
		case 'sondau':
928
			return I18N::translateContext('son’s daughter', 'granddaughter');
929
		case 'sonson':
930
			return I18N::translateContext('son’s son', 'grandson');
931
		case 'sonwif':
932
			return I18N::translateContext('son’s wife', 'daughter-in-law');
933
		case 'spobro':
934
			return I18N::translateContext('spouse’s brother', 'brother-in-law');
935
		case 'spochi':
936
			return I18N::translateContext('spouse’s child', 'step-child');
937
		case 'spodau':
938
			return I18N::translateContext('spouse’s daughter', 'step-daughter');
939
		case 'spofat':
940
			return I18N::translateContext('spouse’s father', 'father-in-law');
941
		case 'spomot':
942
			return I18N::translateContext('spouse’s mother', 'mother-in-law');
943
		case 'sposis':
944
			return I18N::translateContext('spouse’s sister', 'sister-in-law');
945
		case 'sposon':
946
			return I18N::translateContext('spouse’s son', 'step-son');
947
		case 'spopar':
948
			return I18N::translateContext('spouse’s parent', 'mother/father-in-law');
949
		case 'sposib':
950
			return I18N::translateContext('spouse’s sibling', 'brother/sister-in-law');
951
		case 'wifbro':
952
			return I18N::translateContext('wife’s brother', 'brother-in-law');
953
		case 'wifchi':
954
			return I18N::translateContext('wife’s child', 'step-child');
955
		case 'wifdau':
956
			return I18N::translateContext('wife’s daughter', 'step-daughter');
957
		case 'wiffat':
958
			return I18N::translateContext('wife’s father', 'father-in-law');
959
		case 'wifmot':
960
			return I18N::translateContext('wife’s mother', 'mother-in-law');
961
		case 'wifsib':
962
			return I18N::translateContext('wife’s sibling', 'brother/sister-in-law');
963
		case 'wifsis':
964
			return I18N::translateContext('wife’s sister', 'sister-in-law');
965
		case 'wifson':
966
			return I18N::translateContext('wife’s son', 'step-son');
967
968
		// Level Three relationships
969
		// I have commented out some of the unknown-sex relationships that are unlikely to to occur.
970
		// Feel free to add them in, if you think they might be needed
971
		case 'brochichi':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
972
			if ($sex1 === 'M') {
973
				return I18N::translateContext('(a man’s) brother’s child’s child', 'great-nephew/niece');
974
			} else {
975
				return I18N::translateContext('(a woman’s) brother’s child’s child', 'great-nephew/niece');
976
			}
977 View Code Duplication
		case 'brochidau':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
978
			if ($sex1 === 'M') {
979
				return I18N::translateContext('(a man’s) brother’s child’s daughter', 'great-niece');
980
			} else {
981
				return I18N::translateContext('(a woman’s) brother’s child’s daughter', 'great-niece');
982
			}
983 View Code Duplication
		case 'brochison':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
984
			if ($sex1 === 'M') {
985
				return I18N::translateContext('(a man’s) brother’s child’s son', 'great-nephew');
986
			} else {
987
				return I18N::translateContext('(a woman’s) brother’s child’s son', 'great-nephew');
988
			}
989
		case 'brodauchi':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
990
			if ($sex1 === 'M') {
991
				return I18N::translateContext('(a man’s) brother’s daughter’s child', 'great-nephew/niece');
992
			} else {
993
				return I18N::translateContext('(a woman’s) brother’s daughter’s child', 'great-nephew/niece');
994
			}
995 View Code Duplication
		case 'brodaudau':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
996
			if ($sex1 === 'M') {
997
				return I18N::translateContext('(a man’s) brother’s daughter’s daughter', 'great-niece');
998
			} else {
999
				return I18N::translateContext('(a woman’s) brother’s daughter’s daughter', 'great-niece');
1000
			}
1001
		case 'brodauhus':
1002
			return I18N::translateContext('brother’s daughter’s husband', 'nephew-in-law');
1003 View Code Duplication
		case 'brodauson':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1004
			if ($sex1 === 'M') {
1005
				return I18N::translateContext('(a man’s) brother’s daughter’s son', 'great-nephew');
1006
			} else {
1007
				return I18N::translateContext('(a woman’s) brother’s daughter’s son', 'great-nephew');
1008
			}
1009
		case 'brosonchi':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1010
			if ($sex1 === 'M') {
1011
				return I18N::translateContext('(a man’s) brother’s son’s child', 'great-nephew/niece');
1012
			} else {
1013
				return I18N::translateContext('(a woman’s) brother’s son’s child', 'great-nephew/niece');
1014
			}
1015 View Code Duplication
		case 'brosondau':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1016
			if ($sex1 === 'M') {
1017
				return I18N::translateContext('(a man’s) brother’s son’s daughter', 'great-niece');
1018
			} else {
1019
				return I18N::translateContext('(a woman’s) brother’s son’s daughter', 'great-niece');
1020
			}
1021 View Code Duplication
		case 'brosonson':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1022
			if ($sex1 === 'M') {
1023
				return I18N::translateContext('(a man’s) brother’s son’s son', 'great-nephew');
1024
			} else {
1025
				return I18N::translateContext('(a woman’s) brother’s son’s son', 'great-nephew');
1026
			}
1027
		case 'brosonwif':
1028
			return I18N::translateContext('brother’s son’s wife', 'niece-in-law');
1029
		case 'browifbro':
1030
			return I18N::translateContext('brother’s wife’s brother', 'brother-in-law');
1031
		case 'browifsib':
1032
			return I18N::translateContext('brother’s wife’s sibling', 'brother/sister-in-law');
1033
		case 'browifsis':
1034
			return I18N::translateContext('brother’s wife’s sister', 'sister-in-law');
1035
		case 'chichichi':
1036
			return I18N::translateContext('child’s child’s child', 'great-grandchild');
1037
		case 'chichidau':
1038
			return I18N::translateContext('child’s child’s daughter', 'great-granddaughter');
1039
		case 'chichison':
1040
			return I18N::translateContext('child’s child’s son', 'great-grandson');
1041
		case 'chidauchi':
1042
			return I18N::translateContext('child’s daughter’s child', 'great-grandchild');
1043
		case 'chidaudau':
1044
			return I18N::translateContext('child’s daughter’s daughter', 'great-granddaughter');
1045
		case 'chidauhus':
1046
			return I18N::translateContext('child’s daughter’s husband', 'granddaughter’s husband');
1047
		case 'chidauson':
1048
			return I18N::translateContext('child’s daughter’s son', 'great-grandson');
1049
		case 'chisonchi':
1050
			return I18N::translateContext('child’s son’s child', 'great-grandchild');
1051
		case 'chisondau':
1052
			return I18N::translateContext('child’s son’s daughter', 'great-granddaughter');
1053
		case 'chisonson':
1054
			return I18N::translateContext('child’s son’s son', 'great-grandson');
1055
		case 'chisonwif':
1056
			return I18N::translateContext('child’s son’s wife', 'grandson’s wife');
1057
		case 'dauchichi':
1058
			return I18N::translateContext('daughter’s child’s child', 'great-grandchild');
1059
		case 'dauchidau':
1060
			return I18N::translateContext('daughter’s child’s daughter', 'great-granddaughter');
1061
		case 'dauchison':
1062
			return I18N::translateContext('daughter’s child’s son', 'great-grandson');
1063
		case 'daudauchi':
1064
			return I18N::translateContext('daughter’s daughter’s child', 'great-grandchild');
1065
		case 'daudaudau':
1066
			return I18N::translateContext('daughter’s daughter’s daughter', 'great-granddaughter');
1067
		case 'daudauhus':
1068
			return I18N::translateContext('daughter’s daughter’s husband', 'granddaughter’s husband');
1069
		case 'daudauson':
1070
			return I18N::translateContext('daughter’s daughter’s son', 'great-grandson');
1071
		case 'dauhusfat':
1072
			return I18N::translateContext('daughter’s husband’s father', 'son-in-law’s father');
1073
		case 'dauhusmot':
1074
			return I18N::translateContext('daughter’s husband’s mother', 'son-in-law’s mother');
1075
		case 'dauhuspar':
1076
			return I18N::translateContext('daughter’s husband’s parent', 'son-in-law’s parent');
1077
		case 'dausonchi':
1078
			return I18N::translateContext('daughter’s son’s child', 'great-grandchild');
1079
		case 'dausondau':
1080
			return I18N::translateContext('daughter’s son’s daughter', 'great-granddaughter');
1081
		case 'dausonson':
1082
			return I18N::translateContext('daughter’s son’s son', 'great-grandson');
1083
		case 'dausonwif':
1084
			return I18N::translateContext('daughter’s son’s wife', 'grandson’s wife');
1085
		case 'fatbrochi':
1086
			return I18N::translateContext('father’s brother’s child', 'first cousin');
1087
		case 'fatbrodau':
1088
			return I18N::translateContext('father’s brother’s daughter', 'first cousin');
1089
		case 'fatbroson':
1090
			return I18N::translateContext('father’s brother’s son', 'first cousin');
1091
		case 'fatbrowif':
1092
			return I18N::translateContext('father’s brother’s wife', 'aunt');
1093
		case 'fatfatbro':
1094
			return I18N::translateContext('father’s father’s brother', 'great-uncle');
1095
		case 'fatfatfat':
1096
			return I18N::translateContext('father’s father’s father', 'great-grandfather');
1097
		case 'fatfatmot':
1098
			return I18N::translateContext('father’s father’s mother', 'great-grandmother');
1099
		case 'fatfatpar':
1100
			return I18N::translateContext('father’s father’s parent', 'great-grandparent');
1101
		case 'fatfatsib':
1102
			return I18N::translateContext('father’s father’s sibling', 'great-aunt/uncle');
1103
		case 'fatfatsis':
1104
			return I18N::translateContext('father’s father’s sister', 'great-aunt');
1105
		case 'fatmotbro':
1106
			return I18N::translateContext('father’s mother’s brother', 'great-uncle');
1107
		case 'fatmotfat':
1108
			return I18N::translateContext('father’s mother’s father', 'great-grandfather');
1109
		case 'fatmotmot':
1110
			return I18N::translateContext('father’s mother’s mother', 'great-grandmother');
1111
		case 'fatmotpar':
1112
			return I18N::translateContext('father’s mother’s parent', 'great-grandparent');
1113
		case 'fatmotsib':
1114
			return I18N::translateContext('father’s mother’s sibling', 'great-aunt/uncle');
1115
		case 'fatmotsis':
1116
			return I18N::translateContext('father’s mother’s sister', 'great-aunt');
1117
		case 'fatparbro':
1118
			return I18N::translateContext('father’s parent’s brother', 'great-uncle');
1119
		case 'fatparfat':
1120
			return I18N::translateContext('father’s parent’s father', 'great-grandfather');
1121
		case 'fatparmot':
1122
			return I18N::translateContext('father’s parent’s mother', 'great-grandmother');
1123
		case 'fatparpar':
1124
			return I18N::translateContext('father’s parent’s parent', 'great-grandparent');
1125
		case 'fatparsib':
1126
			return I18N::translateContext('father’s parent’s sibling', 'great-aunt/uncle');
1127
		case 'fatparsis':
1128
			return I18N::translateContext('father’s parent’s sister', 'great-aunt');
1129
		case 'fatsischi':
1130
			return I18N::translateContext('father’s sister’s child', 'first cousin');
1131
		case 'fatsisdau':
1132
			return I18N::translateContext('father’s sister’s daughter', 'first cousin');
1133
		case 'fatsishus':
1134
			return I18N::translateContext('father’s sister’s husband', 'uncle');
1135
		case 'fatsisson':
1136
			return I18N::translateContext('father’s sister’s son', 'first cousin');
1137
		case 'fatwifchi':
1138
			return I18N::translateContext('father’s wife’s child', 'step-sibling');
1139
		case 'fatwifdau':
1140
			return I18N::translateContext('father’s wife’s daughter', 'step-sister');
1141
		case 'fatwifson':
1142
			return I18N::translateContext('father’s wife’s son', 'step-brother');
1143
		case 'husbrowif':
1144
			return I18N::translateContext('husband’s brother’s wife', 'sister-in-law');
1145
		case 'hussishus':
1146
			return I18N::translateContext('husband’s sister’s husband', 'brother-in-law');
1147
		case 'motbrochi':
1148
			return I18N::translateContext('mother’s brother’s child', 'first cousin');
1149
		case 'motbrodau':
1150
			return I18N::translateContext('mother’s brother’s daughter', 'first cousin');
1151
		case 'motbroson':
1152
			return I18N::translateContext('mother’s brother’s son', 'first cousin');
1153
		case 'motbrowif':
1154
			return I18N::translateContext('mother’s brother’s wife', 'aunt');
1155
		case 'motfatbro':
1156
			return I18N::translateContext('mother’s father’s brother', 'great-uncle');
1157
		case 'motfatfat':
1158
			return I18N::translateContext('mother’s father’s father', 'great-grandfather');
1159
		case 'motfatmot':
1160
			return I18N::translateContext('mother’s father’s mother', 'great-grandmother');
1161
		case 'motfatpar':
1162
			return I18N::translateContext('mother’s father’s parent', 'great-grandparent');
1163
		case 'motfatsib':
1164
			return I18N::translateContext('mother’s father’s sibling', 'great-aunt/uncle');
1165
		case 'motfatsis':
1166
			return I18N::translateContext('mother’s father’s sister', 'great-aunt');
1167
		case 'mothuschi':
1168
			return I18N::translateContext('mother’s husband’s child', 'step-sibling');
1169
		case 'mothusdau':
1170
			return I18N::translateContext('mother’s husband’s daughter', 'step-sister');
1171
		case 'mothusson':
1172
			return I18N::translateContext('mother’s husband’s son', 'step-brother');
1173
		case 'motmotbro':
1174
			return I18N::translateContext('mother’s mother’s brother', 'great-uncle');
1175
		case 'motmotfat':
1176
			return I18N::translateContext('mother’s mother’s father', 'great-grandfather');
1177
		case 'motmotmot':
1178
			return I18N::translateContext('mother’s mother’s mother', 'great-grandmother');
1179
		case 'motmotpar':
1180
			return I18N::translateContext('mother’s mother’s parent', 'great-grandparent');
1181
		case 'motmotsib':
1182
			return I18N::translateContext('mother’s mother’s sibling', 'great-aunt/uncle');
1183
		case 'motmotsis':
1184
			return I18N::translateContext('mother’s mother’s sister', 'great-aunt');
1185
		case 'motparbro':
1186
			return I18N::translateContext('mother’s parent’s brother', 'great-uncle');
1187
		case 'motparfat':
1188
			return I18N::translateContext('mother’s parent’s father', 'great-grandfather');
1189
		case 'motparmot':
1190
			return I18N::translateContext('mother’s parent’s mother', 'great-grandmother');
1191
		case 'motparpar':
1192
			return I18N::translateContext('mother’s parent’s parent', 'great-grandparent');
1193
		case 'motparsib':
1194
			return I18N::translateContext('mother’s parent’s sibling', 'great-aunt/uncle');
1195
		case 'motparsis':
1196
			return I18N::translateContext('mother’s parent’s sister', 'great-aunt');
1197
		case 'motsischi':
1198
			return I18N::translateContext('mother’s sister’s child', 'first cousin');
1199
		case 'motsisdau':
1200
			return I18N::translateContext('mother’s sister’s daughter', 'first cousin');
1201
		case 'motsishus':
1202
			return I18N::translateContext('mother’s sister’s husband', 'uncle');
1203
		case 'motsisson':
1204
			return I18N::translateContext('mother’s sister’s son', 'first cousin');
1205
		case 'parbrowif':
1206
			return I18N::translateContext('parent’s brother’s wife', 'aunt');
1207
		case 'parfatbro':
1208
			return I18N::translateContext('parent’s father’s brother', 'great-uncle');
1209
		case 'parfatfat':
1210
			return I18N::translateContext('parent’s father’s father', 'great-grandfather');
1211
		case 'parfatmot':
1212
			return I18N::translateContext('parent’s father’s mother', 'great-grandmother');
1213
		case 'parfatpar':
1214
			return I18N::translateContext('parent’s father’s parent', 'great-grandparent');
1215
		case 'parfatsib':
1216
			return I18N::translateContext('parent’s father’s sibling', 'great-aunt/uncle');
1217
		case 'parfatsis':
1218
			return I18N::translateContext('parent’s father’s sister', 'great-aunt');
1219
		case 'parmotbro':
1220
			return I18N::translateContext('parent’s mother’s brother', 'great-uncle');
1221
		case 'parmotfat':
1222
			return I18N::translateContext('parent’s mother’s father', 'great-grandfather');
1223
		case 'parmotmot':
1224
			return I18N::translateContext('parent’s mother’s mother', 'great-grandmother');
1225
		case 'parmotpar':
1226
			return I18N::translateContext('parent’s mother’s parent', 'great-grandparent');
1227
		case 'parmotsib':
1228
			return I18N::translateContext('parent’s mother’s sibling', 'great-aunt/uncle');
1229
		case 'parmotsis':
1230
			return I18N::translateContext('parent’s mother’s sister', 'great-aunt');
1231
		case 'parparbro':
1232
			return I18N::translateContext('parent’s parent’s brother', 'great-uncle');
1233
		case 'parparfat':
1234
			return I18N::translateContext('parent’s parent’s father', 'great-grandfather');
1235
		case 'parparmot':
1236
			return I18N::translateContext('parent’s parent’s mother', 'great-grandmother');
1237
		case 'parparpar':
1238
			return I18N::translateContext('parent’s parent’s parent', 'great-grandparent');
1239
		case 'parparsib':
1240
			return I18N::translateContext('parent’s parent’s sibling', 'great-aunt/uncle');
1241
		case 'parparsis':
1242
			return I18N::translateContext('parent’s parent’s sister', 'great-aunt');
1243
		case 'parsishus':
1244
			return I18N::translateContext('parent’s sister’s husband', 'uncle');
1245
		case 'parspochi':
1246
			return I18N::translateContext('parent’s spouse’s child', 'step-sibling');
1247
		case 'parspodau':
1248
			return I18N::translateContext('parent’s spouse’s daughter', 'step-sister');
1249
		case 'parsposon':
1250
			return I18N::translateContext('parent’s spouse’s son', 'step-brother');
1251
		case 'sibchichi':
1252
			return I18N::translateContext('sibling’s child’s child', 'great-nephew/niece');
1253
		case 'sibchidau':
1254
			return I18N::translateContext('sibling’s child’s daughter', 'great-niece');
1255
		case 'sibchison':
1256
			return I18N::translateContext('sibling’s child’s son', 'great-nephew');
1257
		case 'sibdauchi':
1258
			return I18N::translateContext('sibling’s daughter’s child', 'great-nephew/niece');
1259
		case 'sibdaudau':
1260
			return I18N::translateContext('sibling’s daughter’s daughter', 'great-niece');
1261
		case 'sibdauhus':
1262
			return I18N::translateContext('sibling’s daughter’s husband', 'nephew-in-law');
1263
		case 'sibdauson':
1264
			return I18N::translateContext('sibling’s daughter’s son', 'great-nephew');
1265
		case 'sibsonchi':
1266
			return I18N::translateContext('sibling’s son’s child', 'great-nephew/niece');
1267
		case 'sibsondau':
1268
			return I18N::translateContext('sibling’s son’s daughter', 'great-niece');
1269
		case 'sibsonson':
1270
			return I18N::translateContext('sibling’s son’s son', 'great-nephew');
1271
		case 'sibsonwif':
1272
			return I18N::translateContext('sibling’s son’s wife', 'niece-in-law');
1273
		case 'sischichi':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1274
			if ($sex1 === 'M') {
1275
				return I18N::translateContext('(a man’s) sister’s child’s child', 'great-nephew/niece');
1276
			} else {
1277
				return I18N::translateContext('(a woman’s) sister’s child’s child', 'great-nephew/niece');
1278
			}
1279 View Code Duplication
		case 'sischidau':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1280
			if ($sex1 === 'M') {
1281
				return I18N::translateContext('(a man’s) sister’s child’s daughter', 'great-niece');
1282
			} else {
1283
				return I18N::translateContext('(a woman’s) sister’s child’s daughter', 'great-niece');
1284
			}
1285 View Code Duplication
		case 'sischison':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1286
			if ($sex1 === 'M') {
1287
				return I18N::translateContext('(a man’s) sister’s child’s son', 'great-nephew');
1288
			} else {
1289
				return I18N::translateContext('(a woman’s) sister’s child’s son', 'great-nephew');
1290
			}
1291
		case 'sisdauchi':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1292
			if ($sex1 === 'M') {
1293
				return I18N::translateContext('(a man’s) sister’s daughter’s child', 'great-nephew/niece');
1294
			} else {
1295
				return I18N::translateContext('(a woman’s) sister’s daughter’s child', 'great-nephew/niece');
1296
			}
1297 View Code Duplication
		case 'sisdaudau':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1298
			if ($sex1 === 'M') {
1299
				return I18N::translateContext('(a man’s) sister’s daughter’s daughter', 'great-niece');
1300
			} else {
1301
				return I18N::translateContext('(a woman’s) sister’s daughter’s daughter', 'great-niece');
1302
			}
1303
		case 'sisdauhus':
1304
			return I18N::translateContext('sisters’s daughter’s husband', 'nephew-in-law');
1305 View Code Duplication
		case 'sisdauson':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1306
			if ($sex1 === 'M') {
1307
				return I18N::translateContext('(a man’s) sister’s daughter’s son', 'great-nephew');
1308
			} else {
1309
				return I18N::translateContext('(a woman’s) sister’s daughter’s son', 'great-nephew');
1310
			}
1311
		case 'sishusbro':
1312
			return I18N::translateContext('sister’s husband’s brother', 'brother-in-law');
1313
		case 'sishussib':
1314
			return I18N::translateContext('sister’s husband’s sibling', 'brother/sister-in-law');
1315
		case 'sishussis':
1316
			return I18N::translateContext('sister’s husband’s sister', 'sister-in-law');
1317
		case 'sissonchi':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1318
			if ($sex1 === 'M') {
1319
				return I18N::translateContext('(a man’s) sister’s son’s child', 'great-nephew/niece');
1320
			} else {
1321
				return I18N::translateContext('(a woman’s) sister’s son’s child', 'great-nephew/niece');
1322
			}
1323 View Code Duplication
		case 'sissondau':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1324
			if ($sex1 === 'M') {
1325
				return I18N::translateContext('(a man’s) sister’s son’s daughter', 'great-niece');
1326
			} else {
1327
				return I18N::translateContext('(a woman’s) sister’s son’s daughter', 'great-niece');
1328
			}
1329 View Code Duplication
		case 'sissonson':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1330
			if ($sex1 === 'M') {
1331
				return I18N::translateContext('(a man’s) sister’s son’s son', 'great-nephew');
1332
			} else {
1333
				return I18N::translateContext('(a woman’s) sister’s son’s son', 'great-nephew');
1334
			}
1335
		case 'sissonwif':
1336
			return I18N::translateContext('sisters’s son’s wife', 'niece-in-law');
1337
		case 'sonchichi':
1338
			return I18N::translateContext('son’s child’s child', 'great-grandchild');
1339
		case 'sonchidau':
1340
			return I18N::translateContext('son’s child’s daughter', 'great-granddaughter');
1341
		case 'sonchison':
1342
			return I18N::translateContext('son’s child’s son', 'great-grandson');
1343
		case 'sondauchi':
1344
			return I18N::translateContext('son’s daughter’s child', 'great-grandchild');
1345
		case 'sondaudau':
1346
			return I18N::translateContext('son’s daughter’s daughter', 'great-granddaughter');
1347
		case 'sondauhus':
1348
			return I18N::translateContext('son’s daughter’s husband', 'granddaughter’s husband');
1349
		case 'sondauson':
1350
			return I18N::translateContext('son’s daughter’s son', 'great-grandson');
1351
		case 'sonsonchi':
1352
			return I18N::translateContext('son’s son’s child', 'great-grandchild');
1353
		case 'sonsondau':
1354
			return I18N::translateContext('son’s son’s daughter', 'great-granddaughter');
1355
		case 'sonsonson':
1356
			return I18N::translateContext('son’s son’s son', 'great-grandson');
1357
		case 'sonsonwif':
1358
			return I18N::translateContext('son’s son’s wife', 'grandson’s wife');
1359
		case 'sonwiffat':
1360
			return I18N::translateContext('son’s wife’s father', 'daughter-in-law’s father');
1361
		case 'sonwifmot':
1362
			return I18N::translateContext('son’s wife’s mother', 'daughter-in-law’s mother');
1363
		case 'sonwifpar':
1364
			return I18N::translateContext('son’s wife’s parent', 'daughter-in-law’s parent');
1365
		case 'wifbrowif':
1366
			return I18N::translateContext('wife’s brother’s wife', 'sister-in-law');
1367
		case 'wifsishus':
1368
			return I18N::translateContext('wife’s sister’s husband', 'brother-in-law');
1369
1370
		// Some “special case” level four relationships that have specific names in certain languages
1371
		case 'fatfatbrowif':
1372
			return I18N::translateContext('father’s father’s brother’s wife', 'great-aunt');
1373
		case 'fatfatsibspo':
1374
			return I18N::translateContext('father’s father’s sibling’s spouse', 'great-aunt/uncle');
1375
		case 'fatfatsishus':
1376
			return I18N::translateContext('father’s father’s sister’s husband', 'great-uncle');
1377
		case 'fatmotbrowif':
1378
			return I18N::translateContext('father’s mother’s brother’s wife', 'great-aunt');
1379
		case 'fatmotsibspo':
1380
			return I18N::translateContext('father’s mother’s sibling’s spouse', 'great-aunt/uncle');
1381
		case 'fatmotsishus':
1382
			return I18N::translateContext('father’s mother’s sister’s husband', 'great-uncle');
1383
		case 'fatparbrowif':
1384
			return I18N::translateContext('father’s parent’s brother’s wife', 'great-aunt');
1385
		case 'fatparsibspo':
1386
			return I18N::translateContext('father’s parent’s sibling’s spouse', 'great-aunt/uncle');
1387
		case 'fatparsishus':
1388
			return I18N::translateContext('father’s parent’s sister’s husband', 'great-uncle');
1389
		case 'motfatbrowif':
1390
			return I18N::translateContext('mother’s father’s brother’s wife', 'great-aunt');
1391
		case 'motfatsibspo':
1392
			return I18N::translateContext('mother’s father’s sibling’s spouse', 'great-aunt/uncle');
1393
		case 'motfatsishus':
1394
			return I18N::translateContext('mother’s father’s sister’s husband', 'great-uncle');
1395
		case 'motmotbrowif':
1396
			return I18N::translateContext('mother’s mother’s brother’s wife', 'great-aunt');
1397
		case 'motmotsibspo':
1398
			return I18N::translateContext('mother’s mother’s sibling’s spouse', 'great-aunt/uncle');
1399
		case 'motmotsishus':
1400
			return I18N::translateContext('mother’s mother’s sister’s husband', 'great-uncle');
1401
		case 'motparbrowif':
1402
			return I18N::translateContext('mother’s parent’s brother’s wife', 'great-aunt');
1403
		case 'motparsibspo':
1404
			return I18N::translateContext('mother’s parent’s sibling’s spouse', 'great-aunt/uncle');
1405
		case 'motparsishus':
1406
			return I18N::translateContext('mother’s parent’s sister’s husband', 'great-uncle');
1407
		case 'parfatbrowif':
1408
			return I18N::translateContext('parent’s father’s brother’s wife', 'great-aunt');
1409
		case 'parfatsibspo':
1410
			return I18N::translateContext('parent’s father’s sibling’s spouse', 'great-aunt/uncle');
1411
		case 'parfatsishus':
1412
			return I18N::translateContext('parent’s father’s sister’s husband', 'great-uncle');
1413
		case 'parmotbrowif':
1414
			return I18N::translateContext('parent’s mother’s brother’s wife', 'great-aunt');
1415
		case 'parmotsibspo':
1416
			return I18N::translateContext('parent’s mother’s sibling’s spouse', 'great-aunt/uncle');
1417
		case 'parmotsishus':
1418
			return I18N::translateContext('parent’s mother’s sister’s husband', 'great-uncle');
1419
		case 'parparbrowif':
1420
			return I18N::translateContext('parent’s parent’s brother’s wife', 'great-aunt');
1421
		case 'parparsibspo':
1422
			return I18N::translateContext('parent’s parent’s sibling’s spouse', 'great-aunt/uncle');
1423
		case 'parparsishus':
1424
			return I18N::translateContext('parent’s parent’s sister’s husband', 'great-uncle');
1425
		case 'fatfatbrodau':
1426
			return I18N::translateContext('father’s father’s brother’s daughter', 'first cousin once removed ascending');
1427
		case 'fatfatbroson':
1428
			return I18N::translateContext('father’s father’s brother’s son', 'first cousin once removed ascending');
1429
		case 'fatfatbrochi':
1430
			return I18N::translateContext('father’s father’s brother’s child', 'first cousin once removed ascending');
1431
		case 'fatfatsisdau':
1432
			return I18N::translateContext('father’s father’s sister’s daughter', 'first cousin once removed ascending');
1433
		case 'fatfatsisson':
1434
			return I18N::translateContext('father’s father’s sister’s son', 'first cousin once removed ascending');
1435
		case 'fatfatsischi':
1436
			return I18N::translateContext('father’s father’s sister’s child', 'first cousin once removed ascending');
1437
		case 'fatmotbrodau':
1438
			return I18N::translateContext('father’s mother’s brother’s daughter', 'first cousin once removed ascending');
1439
		case 'fatmotbroson':
1440
			return I18N::translateContext('father’s mother’s brother’s son', 'first cousin once removed ascending');
1441
		case 'fatmotbrochi':
1442
			return I18N::translateContext('father’s mother’s brother’s child', 'first cousin once removed ascending');
1443
		case 'fatmotsisdau':
1444
			return I18N::translateContext('father’s mother’s sister’s daughter', 'first cousin once removed ascending');
1445
		case 'fatmotsisson':
1446
			return I18N::translateContext('father’s mother’s sister’s son', 'first cousin once removed ascending');
1447
		case 'fatmotsischi':
1448
			return I18N::translateContext('father’s mother’s sister’s child', 'first cousin once removed ascending');
1449
		case 'motfatbrodau':
1450
			return I18N::translateContext('mother’s father’s brother’s daughter', 'first cousin once removed ascending');
1451
		case 'motfatbroson':
1452
			return I18N::translateContext('mother’s father’s brother’s son', 'first cousin once removed ascending');
1453
		case 'motfatbrochi':
1454
			return I18N::translateContext('mother’s father’s brother’s child', 'first cousin once removed ascending');
1455
		case 'motfatsisdau':
1456
			return I18N::translateContext('mother’s father’s sister’s daughter', 'first cousin once removed ascending');
1457
		case 'motfatsisson':
1458
			return I18N::translateContext('mother’s father’s sister’s son', 'first cousin once removed ascending');
1459
		case 'motfatsischi':
1460
			return I18N::translateContext('mother’s father’s sister’s child', 'first cousin once removed ascending');
1461
		case 'motmotbrodau':
1462
			return I18N::translateContext('mother’s mother’s brother’s daughter', 'first cousin once removed ascending');
1463
		case 'motmotbroson':
1464
			return I18N::translateContext('mother’s mother’s brother’s son', 'first cousin once removed ascending');
1465
		case 'motmotbrochi':
1466
			return I18N::translateContext('mother’s mother’s brother’s child', 'first cousin once removed ascending');
1467
		case 'motmotsisdau':
1468
			return I18N::translateContext('mother’s mother’s sister’s daughter', 'first cousin once removed ascending');
1469
		case 'motmotsisson':
1470
			return I18N::translateContext('mother’s mother’s sister’s son', 'first cousin once removed ascending');
1471
		case 'motmotsischi':
1472
			return I18N::translateContext('mother’s mother’s sister’s child', 'first cousin once removed ascending');
1473
		}
1474
1475
		// Some “special case” level five relationships that have specific names in certain languages
1476
		if (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)dau$/', $path)) {
1477
			return I18N::translateContext('grandfather’s brother’s granddaughter', 'second cousin');
1478
		} elseif (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)son$/', $path)) {
1479
			return I18N::translateContext('grandfather’s brother’s grandson', 'second cousin');
1480
		} elseif (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)chi$/', $path)) {
1481
			return I18N::translateContext('grandfather’s brother’s grandchild', 'second cousin');
1482
		} elseif (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)dau$/', $path)) {
1483
			return I18N::translateContext('grandfather’s sister’s granddaughter', 'second cousin');
1484
		} elseif (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)son$/', $path)) {
1485
			return I18N::translateContext('grandfather’s sister’s grandson', 'second cousin');
1486
		} elseif (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)chi$/', $path)) {
1487
			return I18N::translateContext('grandfather’s sister’s grandchild', 'second cousin');
1488
		} elseif (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)dau$/', $path)) {
1489
			return I18N::translateContext('grandfather’s sibling’s granddaughter', 'second cousin');
1490
		} elseif (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)son$/', $path)) {
1491
			return I18N::translateContext('grandfather’s sibling’s grandson', 'second cousin');
1492
		} elseif (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)chi$/', $path)) {
1493
			return I18N::translateContext('grandfather’s sibling’s grandchild', 'second cousin');
1494
		} elseif (preg_match('/^(mot|fat|par)motbro(son|dau|chi)dau$/', $path)) {
1495
			return I18N::translateContext('grandmother’s brother’s granddaughter', 'second cousin');
1496
		} elseif (preg_match('/^(mot|fat|par)motbro(son|dau|chi)son$/', $path)) {
1497
			return I18N::translateContext('grandmother’s brother’s grandson', 'second cousin');
1498
		} elseif (preg_match('/^(mot|fat|par)motbro(son|dau|chi)chi$/', $path)) {
1499
			return I18N::translateContext('grandmother’s brother’s grandchild', 'second cousin');
1500
		} elseif (preg_match('/^(mot|fat|par)motsis(son|dau|chi)dau$/', $path)) {
1501
			return I18N::translateContext('grandmother’s sister’s granddaughter', 'second cousin');
1502
		} elseif (preg_match('/^(mot|fat|par)motsis(son|dau|chi)son$/', $path)) {
1503
			return I18N::translateContext('grandmother’s sister’s grandson', 'second cousin');
1504
		} elseif (preg_match('/^(mot|fat|par)motsis(son|dau|chi)chi$/', $path)) {
1505
			return I18N::translateContext('grandmother’s sister’s grandchild', 'second cousin');
1506
		} elseif (preg_match('/^(mot|fat|par)motsib(son|dau|chi)dau$/', $path)) {
1507
			return I18N::translateContext('grandmother’s sibling’s granddaughter', 'second cousin');
1508
		} elseif (preg_match('/^(mot|fat|par)motsib(son|dau|chi)son$/', $path)) {
1509
			return I18N::translateContext('grandmother’s sibling’s grandson', 'second cousin');
1510
		} elseif (preg_match('/^(mot|fat|par)motsib(son|dau|chi)chi$/', $path)) {
1511
			return I18N::translateContext('grandmother’s sibling’s grandchild', 'second cousin');
1512
		} elseif (preg_match('/^(mot|fat|par)parbro(son|dau|chi)dau$/', $path)) {
1513
			return I18N::translateContext('grandparent’s brother’s granddaughter', 'second cousin');
1514
		} elseif (preg_match('/^(mot|fat|par)parbro(son|dau|chi)son$/', $path)) {
1515
			return I18N::translateContext('grandparent’s brother’s grandson', 'second cousin');
1516
		} elseif (preg_match('/^(mot|fat|par)parbro(son|dau|chi)chi$/', $path)) {
1517
			return I18N::translateContext('grandparent’s brother’s grandchild', 'second cousin');
1518
		} elseif (preg_match('/^(mot|fat|par)parsis(son|dau|chi)dau$/', $path)) {
1519
			return I18N::translateContext('grandparent’s sister’s granddaughter', 'second cousin');
1520
		} elseif (preg_match('/^(mot|fat|par)parsis(son|dau|chi)son$/', $path)) {
1521
			return I18N::translateContext('grandparent’s sister’s grandson', 'second cousin');
1522
		} elseif (preg_match('/^(mot|fat|par)parsis(son|dau|chi)chi$/', $path)) {
1523
			return I18N::translateContext('grandparent’s sister’s grandchild', 'second cousin');
1524
		} elseif (preg_match('/^(mot|fat|par)parsib(son|dau|chi)dau$/', $path)) {
1525
			return I18N::translateContext('grandparent’s sibling’s granddaughter', 'second cousin');
1526
		} elseif (preg_match('/^(mot|fat|par)parsib(son|dau|chi)son$/', $path)) {
1527
			return I18N::translateContext('grandparent’s sibling’s grandson', 'second cousin');
1528
		} elseif (preg_match('/^(mot|fat|par)parsib(son|dau|chi)chi$/', $path)) {
1529
			return I18N::translateContext('grandparent’s sibling’s grandchild', 'second cousin');
1530
		}
1531
1532
		// Look for generic/pattern relationships.
1533
		if (preg_match('/^((?:mot|fat|par)+)(bro|sis|sib)$/', $path, $match)) {
1534
			// siblings of direct ancestors
1535
			$up       = strlen($match[1]) / 3;
1536
			$bef_last = substr($path, -6, 3);
1537
			switch ($up) {
1538 View Code Duplication
			case 3:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1539
				switch ($sex2) {
1540
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1541
				if ($bef_last === 'fat') {
1542
				return I18N::translateContext('great-grandfather’s brother', 'great-great-uncle');
1543
				} elseif ($bef_last === 'mot') {
1544
				return I18N::translateContext('great-grandmother’s brother', 'great-great-uncle');
1545
				} else {
1546
				return I18N::translateContext('great-grandparent’s brother', 'great-great-uncle');
1547
				}
1548
				case 'F':
1549
				return I18N::translate('great-great-aunt');
1550
				default:
1551
				return I18N::translate('great-great-aunt/uncle');
1552
				}
1553 View Code Duplication
			case 4:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1554
				switch ($sex2) {
1555
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1556
				if ($bef_last === 'fat') {
1557
				return I18N::translateContext('great-great-grandfather’s brother', 'great-great-great-uncle');
1558
				} elseif ($bef_last === 'mot') {
1559
				return I18N::translateContext('great-great-grandmother’s brother', 'great-great-great-uncle');
1560
				} else {
1561
				return I18N::translateContext('great-great-grandparent’s brother', 'great-great-great-uncle');
1562
				}
1563
				case 'F':
1564
				return I18N::translate('great-great-great-aunt');
1565
				default:
1566
				return I18N::translate('great-great-great-aunt/uncle');
1567
				}
1568 View Code Duplication
			case 5:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1569
				switch ($sex2) {
1570
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1571
				if ($bef_last === 'fat') {
1572
				return I18N::translateContext('great-great-great-grandfather’s brother', 'great ×4 uncle');
1573
				} elseif ($bef_last === 'mot') {
1574
				return I18N::translateContext('great-great-great-grandmother’s brother', 'great ×4 uncle');
1575
				} else {
1576
				return I18N::translateContext('great-great-great-grandparent’s brother', 'great ×4 uncle');
1577
				}
1578
				case 'F':
1579
				return I18N::translate('great ×4 aunt');
1580
				default:
1581
				return I18N::translate('great ×4 aunt/uncle');
1582
				}
1583 View Code Duplication
			case 6:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1584
				switch ($sex2) {
1585
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1586
				if ($bef_last === 'fat') {
1587
				return I18N::translateContext('great ×4 grandfather’s brother', 'great ×5 uncle');
1588
				} elseif ($bef_last === 'mot') {
1589
				return I18N::translateContext('great ×4 grandmother’s brother', 'great ×5 uncle');
1590
				} else {
1591
				return I18N::translateContext('great ×4 grandparent’s brother', 'great ×5 uncle');
1592
				}
1593
				case 'F':
1594
				return I18N::translate('great ×5 aunt');
1595
				default:
1596
				return I18N::translate('great ×5 aunt/uncle');
1597
				}
1598 View Code Duplication
			case 7:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1599
				switch ($sex2) {
1600
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1601
				if ($bef_last === 'fat') {
1602
				return I18N::translateContext('great ×5 grandfather’s brother', 'great ×6 uncle');
1603
				} elseif ($bef_last === 'mot') {
1604
				return I18N::translateContext('great ×5 grandmother’s brother', 'great ×6 uncle');
1605
				} else {
1606
				return I18N::translateContext('great ×5 grandparent’s brother', 'great ×6 uncle');
1607
				}
1608
				case 'F':
1609
				return I18N::translate('great ×6 aunt');
1610
				default:
1611
				return I18N::translate('great ×6 aunt/uncle');
1612
				}
1613 View Code Duplication
			case 8:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1614
				switch ($sex2) {
1615
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1616
				if ($bef_last === 'fat') {
1617
				return I18N::translateContext('great ×6 grandfather’s brother', 'great ×7 uncle');
1618
				} elseif ($bef_last === 'mot') {
1619
				return I18N::translateContext('great ×6 grandmother’s brother', 'great ×7 uncle');
1620
				} else {
1621
				return I18N::translateContext('great ×6 grandparent’s brother', 'great ×7 uncle');
1622
				}
1623
				case 'F':
1624
				return I18N::translate('great ×7 aunt');
1625
				default:
1626
				return I18N::translate('great ×7 aunt/uncle');
1627
				}
1628
			default:
1629
				// Different languages have different rules for naming generations.
1630
				// An English great ×12 uncle is a Danish great ×10 uncle.
1631
				//
1632
				// Need to find out which languages use which rules.
1633
				switch (WT_LOCALE) {
1634 View Code Duplication
				case 'da':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1635
				switch ($sex2) {
1636
				case 'M':
1637
				return I18N::translate('great ×%s uncle', I18N::number($up - 4));
1638
				case 'F':
1639
				return I18N::translate('great ×%s aunt', I18N::number($up - 4));
1640
				default:
1641
				return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 4));
1642
				}
1643
				case 'pl':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1644
					switch ($sex2) {
1645
					case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1646
					if ($bef_last === 'fat') {
1647
					return I18N::translateContext('great ×(%s-1) grandfather’s brother', 'great ×%s uncle', I18N::number($up - 2));
1648
					} elseif ($bef_last === 'mot') {
1649
					return I18N::translateContext('great ×(%s-1) grandmother’s brother', 'great ×%s uncle', I18N::number($up - 2));
1650
					} else {
1651
					return I18N::translateContext('great ×(%s-1) grandparent’s brother', 'great ×%s uncle', I18N::number($up - 2));
1652
					}
1653
					case 'F':
1654
					return I18N::translate('great ×%s aunt', I18N::number($up - 2));
1655
					default:
1656
					return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 2));
1657
					}
1658
				case 'it': // Source: Michele Locati
1659
				case 'en_AU':
1660
				case 'en_GB':
1661
				case 'en_US':
1662 View Code Duplication
				default:
1663
					switch ($sex2) {
1664
					case 'M': // I18N: if you need a different number for %s, contact the developers, as a code-change is required
1665
					return I18N::translate('great ×%s uncle', I18N::number($up - 1));
1666
					case 'F':
1667
					return I18N::translate('great ×%s aunt', I18N::number($up - 1));
1668
					default:
1669
					return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 1));
1670
					}
1671
					}
1672
			}
1673
		}
1674
		if (preg_match('/^(?:bro|sis|sib)((?:son|dau|chi)+)$/', $path, $match)) {
1675
			// direct descendants of siblings
1676
			$down  = strlen($match[1]) / 3 + 1; // Add one, as we count generations from the common ancestor
1677
			$first = substr($path, 0, 3);
1678
			switch ($down) {
1679 View Code Duplication
			case 4:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1680
				switch ($sex2) {
1681
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1682
				if ($first === 'bro' && $sex1 === 'M') {
1683
				return I18N::translateContext('(a man’s) brother’s great-grandson', 'great-great-nephew');
1684
				} elseif ($first === 'sis' && $sex1 === 'M') {
1685
				return I18N::translateContext('(a man’s) sister’s great-grandson', 'great-great-nephew');
1686
				} else {
1687
				return I18N::translateContext('(a woman’s) great-great-nephew', 'great-great-nephew');
1688
				}
1689
				case 'F':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1690
				if ($first === 'bro' && $sex1 === 'M') {
1691
				return I18N::translateContext('(a man’s) brother’s great-granddaughter', 'great-great-niece');
1692
				} elseif ($first === 'sis' && $sex1 === 'M') {
1693
				return I18N::translateContext('(a man’s) sister’s great-granddaughter', 'great-great-niece');
1694
				} else {
1695
				return I18N::translateContext('(a woman’s) great-great-niece', 'great-great-niece');
1696
				}
1697
				default:
1698
				if ($first === 'bro' && $sex1 === 'M') {
1699
				return I18N::translateContext('(a man’s) brother’s great-grandchild', 'great-great-nephew/niece');
1700
				} elseif ($first === 'sis' && $sex1 === 'M') {
1701
				return I18N::translateContext('(a man’s) sister’s great-grandchild', 'great-great-nephew/niece');
1702
				} else {
1703
				return I18N::translateContext('(a woman’s) great-great-nephew/niece', 'great-great-nephew/niece');
1704
				}
1705
				}
1706 View Code Duplication
			case 5:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1707
				switch ($sex2) {
1708
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1709
				if ($first === 'bro' && $sex1 === 'M') {
1710
				return I18N::translateContext('(a man’s) brother’s great-great-grandson', 'great-great-great-nephew');
1711
				} elseif ($first === 'sis' && $sex1 === 'M') {
1712
				return I18N::translateContext('(a man’s) sister’s great-great-grandson', 'great-great-great-nephew');
1713
				} else {
1714
				return I18N::translateContext('(a woman’s) great-great-great-nephew', 'great-great-great-nephew');
1715
				}
1716
				case 'F':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1717
				if ($first === 'bro' && $sex1 === 'M') {
1718
				return I18N::translateContext('(a man’s) brother’s great-great-granddaughter', 'great-great-great-niece');
1719
				} elseif ($first === 'sis' && $sex1 === 'M') {
1720
				return I18N::translateContext('(a man’s) sister’s great-great-granddaughter', 'great-great-great-niece');
1721
				} else {
1722
				return I18N::translateContext('(a woman’s) great-great-great-niece', 'great-great-great-niece');
1723
				}
1724
				default:
1725
				if ($first === 'bro' && $sex1 === 'M') {
1726
				return I18N::translateContext('(a man’s) brother’s great-great-grandchild', 'great-great-great-nephew/niece');
1727
				} elseif ($first === 'sis' && $sex1 === 'M') {
1728
				return I18N::translateContext('(a man’s) sister’s great-great-grandchild', 'great-great-great-nephew/niece');
1729
				} else {
1730
				return I18N::translateContext('(a woman’s) great-great-great-nephew/niece', 'great-great-great-nephew/niece');
1731
				}
1732
				}
1733 View Code Duplication
			case 6:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1734
				switch ($sex2) {
1735
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1736
				if ($first === 'bro' && $sex1 === 'M') {
1737
				return I18N::translateContext('(a man’s) brother’s great-great-great-grandson', 'great ×4 nephew');
1738
				} elseif ($first === 'sis' && $sex1 === 'M') {
1739
				return I18N::translateContext('(a man’s) sister’s great-great-great-grandson', 'great ×4 nephew');
1740
				} else {
1741
				return I18N::translateContext('(a woman’s) great ×4 nephew', 'great ×4 nephew');
1742
				}
1743
				case 'F':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1744
				if ($first === 'bro' && $sex1 === 'M') {
1745
				return I18N::translateContext('(a man’s) brother’s great-great-great-granddaughter', 'great ×4 niece');
1746
				} elseif ($first === 'sis' && $sex1 === 'M') {
1747
				return I18N::translateContext('(a man’s) sister’s great-great-great-granddaughter', 'great ×4 niece');
1748
				} else {
1749
				return I18N::translateContext('(a woman’s) great ×4 niece', 'great ×4 niece');
1750
				}
1751
				default:
1752
				if ($first === 'bro' && $sex1 === 'M') {
1753
				return I18N::translateContext('(a man’s) brother’s great-great-great-grandchild', 'great ×4 nephew/niece');
1754
				} elseif ($first === 'sis' && $sex1 === 'M') {
1755
				return I18N::translateContext('(a man’s) sister’s great-great-great-grandchild', 'great ×4 nephew/niece');
1756
				} else {
1757
				return I18N::translateContext('(a woman’s) great ×4 nephew/niece', 'great ×4 nephew/niece');
1758
				}
1759
				}
1760 View Code Duplication
			case 7:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1761
				switch ($sex2) {
1762
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1763
				if ($first === 'bro' && $sex1 === 'M') {
1764
				return I18N::translateContext('(a man’s) brother’s great ×4 grandson', 'great ×5 nephew');
1765
				} elseif ($first === 'sis' && $sex1 === 'M') {
1766
				return I18N::translateContext('(a man’s) sister’s great ×4 grandson', 'great ×5 nephew');
1767
				} else {
1768
				return I18N::translateContext('(a woman’s) great ×5 nephew', 'great ×5 nephew');
1769
				}
1770
				case 'F':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1771
				if ($first === 'bro' && $sex1 === 'M') {
1772
				return I18N::translateContext('(a man’s) brother’s great ×4 granddaughter', 'great ×5 niece');
1773
				} elseif ($first === 'sis' && $sex1 === 'M') {
1774
				return I18N::translateContext('(a man’s) sister’s great ×4 granddaughter', 'great ×5 niece');
1775
				} else {
1776
				return I18N::translateContext('(a woman’s) great ×5 niece', 'great ×5 niece');
1777
				}
1778
				default:
1779
				if ($first === 'bro' && $sex1 === 'M') {
1780
				return I18N::translateContext('(a man’s) brother’s great ×4 grandchild', 'great ×5 nephew/niece');
1781
				} elseif ($first === 'sis' && $sex1 === 'M') {
1782
				return I18N::translateContext('(a man’s) sister’s great ×4 grandchild', 'great ×5 nephew/niece');
1783
				} else {
1784
				return I18N::translateContext('(a woman’s) great ×5 nephew/niece', 'great ×5 nephew/niece');
1785
				}
1786
				}
1787
			default:
1788
				// Different languages have different rules for naming generations.
1789
				// An English great ×12 nephew is a Polish great ×11 nephew.
1790
				//
1791
				// Need to find out which languages use which rules.
1792
				switch (WT_LOCALE) {
1793
				case 'pl': // Source: Lukasz Wilenski
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1794
				switch ($sex2) {
1795 View Code Duplication
				case 'M':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1796
				if ($first === 'bro' && $sex1 === 'M') {
1797
				return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 3));
1798
				} elseif ($first === 'sis' && $sex1 === 'M') {
1799
				return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 3));
1800
				} else {
1801
				return I18N::translateContext('(a woman’s) great ×%s nephew', 'great ×%s nephew', I18N::number($down - 3));
1802
				}
1803 View Code Duplication
				case 'F':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1804
				if ($first === 'bro' && $sex1 === 'M') {
1805
				return I18N::translateContext('(a man’s) brother’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 3));
1806
				} elseif ($first === 'sis' && $sex1 === 'M') {
1807
				return I18N::translateContext('(a man’s) sister’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 3));
1808
				} else {
1809
				return I18N::translateContext('(a woman’s) great ×%s niece', 'great ×%s niece', I18N::number($down - 3));
1810
				}
1811 View Code Duplication
				default:
1812
				if ($first === 'bro' && $sex1 === 'M') {
1813
				return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 3));
1814
				} elseif ($first === 'sis' && $sex1 === 'M') {
1815
				return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 3));
1816
				} else {
1817
				return I18N::translateContext('(a woman’s) great ×%s nephew/niece', 'great ×%s nephew/niece', I18N::number($down - 3));
1818
				}
1819
				}
1820 View Code Duplication
				case 'he': // Source: Meliza Amity
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1821
					switch ($sex2) {
1822
					case 'M':
1823
					return I18N::translate('great ×%s nephew', I18N::number($down - 1));
1824
					case 'F':
1825
					return I18N::translate('great ×%s niece', I18N::number($down - 1));
1826
					default:
1827
					return I18N::translate('great ×%s nephew/niece', I18N::number($down - 1));
1828
					}
1829
				case 'it': // Source: Michele Locati.
1830
				case 'en_AU':
1831
				case 'en_GB':
1832
				case 'en_US':
1833 View Code Duplication
				default:
1834
					switch ($sex2) {
1835
					case 'M': // I18N: if you need a different number for %s, contact the developers, as a code-change is required
1836
					return I18N::translate('great ×%s nephew', I18N::number($down - 2));
1837
					case 'F':
1838
					return I18N::translate('great ×%s niece', I18N::number($down - 2));
1839
					default:
1840
					return I18N::translate('great ×%s nephew/niece', I18N::number($down - 2));
1841
					}
1842
					}
1843
			}
1844
		}
1845
		if (preg_match('/^((?:mot|fat|par)*)$/', $path, $match)) {
1846
			// direct ancestors
1847
			$up = strlen($match[1]) / 3;
1848
			switch ($up) {
1849
			case 4:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1850
				switch ($sex2) {
1851
				case 'M':
1852
				return I18N::translate('great-great-grandfather');
1853
				case 'F':
1854
				return I18N::translate('great-great-grandmother');
1855
				default:
1856
				return I18N::translate('great-great-grandparent');
1857
				}
1858
			case 5:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1859
				switch ($sex2) {
1860
				case 'M':
1861
				return I18N::translate('great-great-great-grandfather');
1862
				case 'F':
1863
				return I18N::translate('great-great-great-grandmother');
1864
				default:
1865
				return I18N::translate('great-great-great-grandparent');
1866
				}
1867 View Code Duplication
			case 6:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1868
				switch ($sex2) {
1869
				case 'M':
1870
				return I18N::translate('great ×4 grandfather');
1871
				case 'F':
1872
				return I18N::translate('great ×4 grandmother');
1873
				default:
1874
				return I18N::translate('great ×4 grandparent');
1875
				}
1876 View Code Duplication
			case 7:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1877
				switch ($sex2) {
1878
				case 'M':
1879
				return I18N::translate('great ×5 grandfather');
1880
				case 'F':
1881
				return I18N::translate('great ×5 grandmother');
1882
				default:
1883
				return I18N::translate('great ×5 grandparent');
1884
				}
1885 View Code Duplication
			case 8:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1886
				switch ($sex2) {
1887
				case 'M':
1888
				return I18N::translate('great ×6 grandfather');
1889
				case 'F':
1890
				return I18N::translate('great ×6 grandmother');
1891
				default:
1892
				return I18N::translate('great ×6 grandparent');
1893
				}
1894 View Code Duplication
			case 9:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1895
				switch ($sex2) {
1896
				case 'M':
1897
				return I18N::translate('great ×7 grandfather');
1898
				case 'F':
1899
				return I18N::translate('great ×7 grandmother');
1900
				default:
1901
				return I18N::translate('great ×7 grandparent');
1902
				}
1903
			default:
1904
				// Different languages have different rules for naming generations.
1905
				// An English great ×12 grandfather is a Danish great ×11 grandfather.
1906
				//
1907
				// Need to find out which languages use which rules.
1908
				switch (WT_LOCALE) {
1909 View Code Duplication
				case 'da': // Source: Patrick Sorensen
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1910
				switch ($sex2) {
1911
				case 'M':
1912
				return I18N::translate('great ×%s grandfather', I18N::number($up - 3));
1913
				case 'F':
1914
				return I18N::translate('great ×%s grandmother', I18N::number($up - 3));
1915
				default:
1916
				return I18N::translate('great ×%s grandparent', I18N::number($up - 3));
1917
				}
1918
				case 'it': // Source: Michele Locati
1919
				case 'es': // Source: Wes Groleau
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1920
					switch ($sex2) {
1921
					case 'M':
1922
					return I18N::translate('great ×%s grandfather', I18N::number($up));
1923
					case 'F':
1924
					return I18N::translate('great ×%s grandmother', I18N::number($up));
1925
					default:
1926
					return I18N::translate('great ×%s grandparent', I18N::number($up));
1927
					}
1928
				case 'fr': // Source: Jacqueline Tetreault
1929 View Code Duplication
				case 'fr_CA':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1930
					switch ($sex2) {
1931
					case 'M':
1932
					return I18N::translate('great ×%s grandfather', I18N::number($up - 1));
1933
					case 'F':
1934
					return I18N::translate('great ×%s grandmother', I18N::number($up - 1));
1935
					default:
1936
					return I18N::translate('great ×%s grandparent', I18N::number($up - 1));
1937
					}
1938
				case 'nn': // Source: Hogne Røed Nilsen (https://bugs.launchpad.net/webtrees/+bug/1168553)
1939 View Code Duplication
				case 'nb':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1940
					switch ($sex2) {
1941
					case 'M': // I18N: if you need a different number for %s, contact the developers, as a code-change is required
1942
					return I18N::translate('great ×%s grandfather', I18N::number($up - 3));
1943
					case 'F':
1944
					return I18N::translate('great ×%s grandmother', I18N::number($up - 3));
1945
					default:
1946
					return I18N::translate('great ×%s grandparent', I18N::number($up - 3));
1947
					}
1948
				case 'en_AU':
1949
				case 'en_GB':
1950
				case 'en_US':
1951 View Code Duplication
				default:
1952
					switch ($sex2) {
1953
					case 'M': // 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
					case 'F':
1956
					return I18N::translate('great ×%s grandmother', I18N::number($up - 2));
1957
					default:
1958
					return I18N::translate('great ×%s grandparent', I18N::number($up - 2));
1959
					}
1960
					}
1961
			}
1962
		}
1963
		if (preg_match('/^((?:son|dau|chi)*)$/', $path, $match)) {
1964
			// direct descendants
1965
			$up = strlen($match[1]) / 3;
1966
			switch ($up) {
1967
			case 4:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1968
				switch ($sex2) {
1969
				case 'M':
1970
				return I18N::translate('great-great-grandson');
1971
				case 'F':
1972
				return I18N::translate('great-great-granddaughter');
1973
				default:
1974
				return I18N::translate('great-great-grandchild');
1975
				}
1976
1977
			case 5:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1978
				switch ($sex2) {
1979
				case 'M':
1980
				return I18N::translate('great-great-great-grandson');
1981
				case 'F':
1982
				return I18N::translate('great-great-great-granddaughter');
1983
				default:
1984
				return I18N::translate('great-great-great-grandchild');
1985
				}
1986
1987 View Code Duplication
			case 6:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1988
				switch ($sex2) {
1989
				case 'M':
1990
				return I18N::translate('great ×4 grandson');
1991
				case 'F':
1992
				return I18N::translate('great ×4 granddaughter');
1993
				default:
1994
				return I18N::translate('great ×4 grandchild');
1995
				}
1996
1997 View Code Duplication
			case 7:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1998
				switch ($sex2) {
1999
				case 'M':
2000
				return I18N::translate('great ×5 grandson');
2001
				case 'F':
2002
				return I18N::translate('great ×5 granddaughter');
2003
				default:
2004
				return I18N::translate('great ×5 grandchild');
2005
				}
2006
2007 View Code Duplication
			case 8:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
2008
				switch ($sex2) {
2009
				case 'M':
2010
				return I18N::translate('great ×6 grandson');
2011
				case 'F':
2012
				return I18N::translate('great ×6 granddaughter');
2013
				default:
2014
				return I18N::translate('great ×6 grandchild');
2015
				}
2016
2017 View Code Duplication
			case 9:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
2018
				switch ($sex2) {
2019
				case 'M':
2020
				return I18N::translate('great ×7 grandson');
2021
				case 'F':
2022
				return I18N::translate('great ×7 granddaughter');
2023
				default:
2024
				return I18N::translate('great ×7 grandchild');
2025
				}
2026
2027
			default:
2028
				// Different languages have different rules for naming generations.
2029
				// An English great ×12 grandson is a Danish great ×11 grandson.
2030
				//
2031
				// Need to find out which languages use which rules.
2032
				switch (WT_LOCALE) {
2033
				case 'nn': // Source: Hogne Røed Nilsen
2034
				case 'nb':
2035 View Code Duplication
				case 'da': // Source: Patrick Sorensen
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
2036
				switch ($sex2) {
2037
				case 'M':
2038
				return I18N::translate('great ×%s grandson', I18N::number($up - 3));
2039
				case 'F':
2040
				return I18N::translate('great ×%s granddaughter', I18N::number($up - 3));
2041
				default:
2042
				return I18N::translate('great ×%s grandchild', I18N::number($up - 3));
2043
				}
2044
				case 'it': // Source: Michele Locati
2045
				case 'es': // Source: Wes Groleau (adding doesn’t change behavior, but needs to be better researched)
2046
				case 'en_AU':
2047
				case 'en_GB':
2048
				case 'en_US':
2049 View Code Duplication
				default:
2050
					switch ($sex2) {
2051
2052
					case 'M': // I18N: if you need a different number for %s, contact the developers, as a code-change is required
2053
					return I18N::translate('great ×%s grandson', I18N::number($up - 2));
2054
					case 'F':
2055
					return I18N::translate('great ×%s granddaughter', I18N::number($up - 2));
2056
					default:
2057
					return I18N::translate('great ×%s grandchild', I18N::number($up - 2));
2058
					}
2059
					}
2060
			}
2061
		}
2062
		if (preg_match('/^((?:mot|fat|par)+)(?:bro|sis|sib)((?:son|dau|chi)+)$/', $path, $match)) {
2063
			// cousins in English
2064
			$ascent  = $match[1];
2065
			$descent = $match[2];
2066
			$up      = strlen($ascent) / 3;
2067
			$down    = strlen($descent) / 3;
2068
			$cousin  = min($up, $down); // Moved out of switch (en/default case) so that
2069
			$removed = abs($down - $up); // Spanish (and other languages) can use it, too.
2070
2071
			// Different languages have different rules for naming cousins. For example,
2072
			// an English “second cousin once removed” is a Polish “cousin of 7th degree”.
2073
			//
2074
			// Need to find out which languages use which rules.
2075
			switch (WT_LOCALE) {
2076
			case 'pl': // Source: Lukasz Wilenski
2077
				return self::cousinName($up + $down + 2, $sex2);
2078
			case 'it':
2079
				// Source: Michele Locati. See italian_cousins_names.zip
2080
				// https://webtrees.net/forums/8-translation/1200-great-xn-grandparent?limit=6&start=6
2081
				return self::cousinName($up + $down - 3, $sex2);
2082
			case 'es':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
2083
				// Source: Wes Groleau. See http://UniGen.us/Parentesco.html & http://UniGen.us/Parentesco-D.html
2084
				if ($down == $up) {
2085
					return self::cousinName($cousin, $sex2);
2086
				} elseif ($down < $up) {
2087
					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sib' . $descent, null, null));
2088
				} else {
2089
					switch ($sex2) {
2090 View Code Duplication
					case 'M':
2091
					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('bro' . $descent, null, null));
2092 View Code Duplication
					case 'F':
2093
					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sis' . $descent, null, null));
2094 View Code Duplication
					default:
2095
					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sib' . $descent, null, null));
2096
					}
2097
					}
2098
			case 'en_AU': // See: http://en.wikipedia.org/wiki/File:CousinTree.svg
2099
			case 'en_GB':
2100
			case 'en_US':
2101
			default:
2102
				switch ($removed) {
2103
				case 0:
2104
				return self::cousinName($cousin, $sex2);
2105 View Code Duplication
				case 1:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
2106
				if ($up > $down) {
2107
				/* I18N: %s=“fifth cousin”, etc. http://www.ancestry.com/learn/library/article.aspx?article=2856 */
2108
				return I18N::translate('%s once removed ascending', self::cousinName($cousin, $sex2));
2109
				} else {
2110
				/* I18N: %s=“fifth cousin”, etc. http://www.ancestry.com/learn/library/article.aspx?article=2856 */
2111
				return I18N::translate('%s once removed descending', self::cousinName($cousin, $sex2));
2112
				}
2113 View Code Duplication
				case 2:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
2114
				if ($up > $down) {
2115
				/* I18N: %s=“fifth cousin”, etc. */
2116
				return I18N::translate('%s twice removed ascending', self::cousinName($cousin, $sex2));
2117
				} else {
2118
				/* I18N: %s=“fifth cousin”, etc. */
2119
				return I18N::translate('%s twice removed descending', self::cousinName($cousin, $sex2));
2120
				}
2121 View Code Duplication
				case 3:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
2122
				if ($up > $down) {
2123
				/* I18N: %s=“fifth cousin”, etc. */
2124
				return I18N::translate('%s three times removed ascending', self::cousinName($cousin, $sex2));
2125
				} else {
2126
				/* I18N: %s=“fifth cousin”, etc. */
2127
				return I18N::translate('%s three times removed descending', self::cousinName($cousin, $sex2));
2128
				}
2129
				default:
2130
				if ($up > $down) {
2131
				/* I18N: %1$s=“fifth cousin”, etc., %2$s>=4 */
2132
				return I18N::translate('%1$s %2$s times removed ascending', self::cousinName($cousin, $sex2), I18N::number($removed));
2133
				} else {
2134
				/* I18N: %1$s=“fifth cousin”, etc., %2$s>=4 */
2135
				return I18N::translate('%1$s %2$s times removed descending', self::cousinName($cousin, $sex2), I18N::number($removed));
2136
				}
2137
				}
2138
			}
2139
		}
2140
2141
		// Split the relationship into sub-relationships, e.g., third-cousin’s great-uncle.
2142
		// Try splitting at every point, and choose the path with the shorted translated name.
2143
		// But before starting to recursively go through all combinations, do a cache look-up
2144
		if (array_key_exists($path, self::$relationshipsCache)) {
2145
			return self::$relationshipsCache[$path];
2146
		}
2147
2148
		$relationship = null;
2149
		$path1        = substr($path, 0, 3);
2150
		$path2        = substr($path, 3);
2151
		while ($path2) {
2152
			$tmp = I18N::translate(
2153
			// I18N: A complex relationship, such as “third-cousin’s great-uncle”
2154
				'%1$s’s %2$s',
2155
				self::getRelationshipNameFromPath($path1, null, null), // TODO: need the actual people
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
2156
				self::getRelationshipNameFromPath($path2, null, null)
2157
			);
2158
			if (!$relationship || strlen($tmp) < strlen($relationship)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $relationship of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2159
				$relationship = $tmp;
2160
			}
2161
			$path1 .= substr($path2, 0, 3);
2162
			$path2 = substr($path2, 3);
2163
		}
2164
		// and store the result in the cache
2165
		self::$relationshipsCache[$path] = $relationship;
2166
2167
		return $relationship;
2168
	}
2169
2170
	/**
2171
	 * Function to build an URL querystring from GET variables
2172
	 * Optionally, add/replace specified values
2173
	 *
2174
	 * @param null|string[] $overwrite
2175
	 * @param null|string $separator
2176
	 *
2177
	 * @return string
2178
	 */
2179
	public static function getQueryUrl($overwrite = null, $separator = '&') {
0 ignored issues
show
Coding Style introduced by
getQueryUrl uses the super-global variable $_GET which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
2180
		if (empty($_GET)) {
2181
			$get = array();
2182
		} else {
2183
			$get = $_GET;
2184
		}
2185
		if (is_array($overwrite)) {
2186
			foreach ($overwrite as $key => $value) {
2187
				$get[$key] = $value;
2188
			}
2189
		}
2190
2191
		$query_string = '';
2192
		foreach ($get as $key => $value) {
2193
			if (!is_array($value)) {
2194
				$query_string .= $separator . rawurlencode($key) . '=' . rawurlencode($value);
2195
			} else {
2196
				foreach ($value as $k => $v) {
2197
					$query_string .= $separator . rawurlencode($key) . '%5B' . rawurlencode($k) . '%5D=' . rawurlencode($v);
2198
				}
2199
			}
2200
		}
2201
		$query_string = substr($query_string, strlen($separator)); // Remove leading “&amp;”
2202
		if ($query_string) {
2203
			return WT_SCRIPT_NAME . '?' . $query_string;
2204
		} else {
2205
			return WT_SCRIPT_NAME;
2206
		}
2207
	}
2208
2209
	/**
2210
	 * Determines whether the passed in filename is a link to an external source (i.e. contains “://”)
2211
	 *
2212
	 * @param string $file
2213
	 *
2214
	 * @return bool
2215
	 */
2216
	public static function isFileExternal($file) {
2217
		return strpos($file, '://') !== false;
2218
	}
2219
}
2220