Passed
Push — 1.7 ( 23cbb7...8df8a8 )
by Greg
08:15
created
app/Report/ReportHtmlTextbox.php 2 patches
Indentation   +237 added lines, -237 removed lines patch added patch discarded remove patch
@@ -19,253 +19,253 @@
 block discarded – undo
19 19
  * Class ReportHtmlTextbox
20 20
  */
21 21
 class ReportHtmlTextbox extends ReportBaseTextbox {
22
-	/**
23
-	 * Render the elements.
24
-	 *
25
-	 * @param ReportHtml $renderer
26
-	 */
27
-	public function render($renderer) {
28
-		// checkFootnote
29
-		$newelements      = array();
30
-		$lastelement      = array();
31
-		$footnote_element = array();
32
-		// Element counter
33
-		$cE = count($this->elements);
34
-		//-- collapse duplicate elements
35
-		for ($i = 0; $i < $cE; $i++) {
36
-			$element = $this->elements[$i];
37
-			if (is_object($element)) {
38
-				if ($element instanceof ReportBaseText) {
39
-					if (!empty($footnote_element)) {
40
-						ksort($footnote_element);
41
-						foreach ($footnote_element as $links) {
42
-							$newelements[] = $links;
43
-						}
44
-						$footnote_element = array();
45
-					}
46
-					if (empty($lastelement)) {
47
-						$lastelement = $element;
48
-					} else {
49
-						// Checking if the Text has the same style
50
-						if ($element->getStyleName() == $lastelement->getStyleName()) {
51
-							$lastelement->addText(str_replace("\n", "<br>", $element->getValue()));
52
-						} elseif (!empty($lastelement)) {
53
-							$newelements[] = $lastelement;
54
-							$lastelement   = $element;
55
-						}
56
-					}
57
-				} // Collect the Footnote links
58
-				elseif ($element instanceof ReportBaseFootnote) {
59
-					// Check if the Footnote has been set with it’s link number
60
-					$renderer->checkFootnote($element);
61
-					// Save first the last element if any
62
-					if (!empty($lastelement)) {
63
-						$newelements[] = $lastelement;
64
-						$lastelement   = array();
65
-					}
66
-					// Save the Footnote with it’s link number as key for sorting later
67
-					$footnote_element[$element->num] = $element;
68
-				} //-- do not keep empty footnotes
69
-				elseif (!($element instanceof ReportBaseFootnote) || trim($element->getValue()) != "") {
70
-					if (!empty($footnote_element)) {
71
-						ksort($footnote_element);
72
-						foreach ($footnote_element as $links) {
73
-							$newelements[] = $links;
74
-						}
75
-						$footnote_element = array();
76
-					}
77
-					if (!empty($lastelement)) {
78
-						$newelements[] = $lastelement;
79
-						$lastelement   = array();
80
-					}
81
-					$newelements[] = $element;
82
-				}
83
-			} else {
84
-				if (!empty($lastelement)) {
85
-					$newelements[] = $lastelement;
86
-					$lastelement   = array();
87
-				}
88
-				if (!empty($footnote_element)) {
89
-					ksort($footnote_element);
90
-					foreach ($footnote_element as $links) {
91
-						$newelements[] = $links;
92
-					}
93
-					$footnote_element = array();
94
-				}
95
-				$newelements[] = $element;
96
-			}
97
-		}
98
-		if (!empty($lastelement)) {
99
-			$newelements[] = $lastelement;
100
-		}
101
-		if (!empty($footnote_element)) {
102
-			ksort($footnote_element);
103
-			foreach ($footnote_element as $links) {
104
-				$newelements[] = $links;
105
-			}
106
-		}
107
-		$this->elements = $newelements;
108
-		unset($footnote_element, $lastelement, $links, $newelements);
22
+    /**
23
+     * Render the elements.
24
+     *
25
+     * @param ReportHtml $renderer
26
+     */
27
+    public function render($renderer) {
28
+        // checkFootnote
29
+        $newelements      = array();
30
+        $lastelement      = array();
31
+        $footnote_element = array();
32
+        // Element counter
33
+        $cE = count($this->elements);
34
+        //-- collapse duplicate elements
35
+        for ($i = 0; $i < $cE; $i++) {
36
+            $element = $this->elements[$i];
37
+            if (is_object($element)) {
38
+                if ($element instanceof ReportBaseText) {
39
+                    if (!empty($footnote_element)) {
40
+                        ksort($footnote_element);
41
+                        foreach ($footnote_element as $links) {
42
+                            $newelements[] = $links;
43
+                        }
44
+                        $footnote_element = array();
45
+                    }
46
+                    if (empty($lastelement)) {
47
+                        $lastelement = $element;
48
+                    } else {
49
+                        // Checking if the Text has the same style
50
+                        if ($element->getStyleName() == $lastelement->getStyleName()) {
51
+                            $lastelement->addText(str_replace("\n", "<br>", $element->getValue()));
52
+                        } elseif (!empty($lastelement)) {
53
+                            $newelements[] = $lastelement;
54
+                            $lastelement   = $element;
55
+                        }
56
+                    }
57
+                } // Collect the Footnote links
58
+                elseif ($element instanceof ReportBaseFootnote) {
59
+                    // Check if the Footnote has been set with it’s link number
60
+                    $renderer->checkFootnote($element);
61
+                    // Save first the last element if any
62
+                    if (!empty($lastelement)) {
63
+                        $newelements[] = $lastelement;
64
+                        $lastelement   = array();
65
+                    }
66
+                    // Save the Footnote with it’s link number as key for sorting later
67
+                    $footnote_element[$element->num] = $element;
68
+                } //-- do not keep empty footnotes
69
+                elseif (!($element instanceof ReportBaseFootnote) || trim($element->getValue()) != "") {
70
+                    if (!empty($footnote_element)) {
71
+                        ksort($footnote_element);
72
+                        foreach ($footnote_element as $links) {
73
+                            $newelements[] = $links;
74
+                        }
75
+                        $footnote_element = array();
76
+                    }
77
+                    if (!empty($lastelement)) {
78
+                        $newelements[] = $lastelement;
79
+                        $lastelement   = array();
80
+                    }
81
+                    $newelements[] = $element;
82
+                }
83
+            } else {
84
+                if (!empty($lastelement)) {
85
+                    $newelements[] = $lastelement;
86
+                    $lastelement   = array();
87
+                }
88
+                if (!empty($footnote_element)) {
89
+                    ksort($footnote_element);
90
+                    foreach ($footnote_element as $links) {
91
+                        $newelements[] = $links;
92
+                    }
93
+                    $footnote_element = array();
94
+                }
95
+                $newelements[] = $element;
96
+            }
97
+        }
98
+        if (!empty($lastelement)) {
99
+            $newelements[] = $lastelement;
100
+        }
101
+        if (!empty($footnote_element)) {
102
+            ksort($footnote_element);
103
+            foreach ($footnote_element as $links) {
104
+                $newelements[] = $links;
105
+            }
106
+        }
107
+        $this->elements = $newelements;
108
+        unset($footnote_element, $lastelement, $links, $newelements);
109 109
 
110
-		$cP = 0; // Class Padding
110
+        $cP = 0; // Class Padding
111 111
 
112
-		// Used with line breaks and cell height calculation within this box only
113
-		$renderer->largestFontHeight = 0;
112
+        // Used with line breaks and cell height calculation within this box only
113
+        $renderer->largestFontHeight = 0;
114 114
 
115
-		// Current position
116
-		if ($this->left == ".") {
117
-			$cX = $renderer->getX();
118
-		} else {
119
-			$cX = $this->left;
120
-			$renderer->setX($cX);
121
-		}
122
-		// Current position (top)
123
-		if ($this->top == ".") {
124
-			$this->top = $renderer->getY();
125
-		} else {
126
-			$renderer->setY($this->top);
127
-		}
115
+        // Current position
116
+        if ($this->left == ".") {
117
+            $cX = $renderer->getX();
118
+        } else {
119
+            $cX = $this->left;
120
+            $renderer->setX($cX);
121
+        }
122
+        // Current position (top)
123
+        if ($this->top == ".") {
124
+            $this->top = $renderer->getY();
125
+        } else {
126
+            $renderer->setY($this->top);
127
+        }
128 128
 
129
-		// Check the width if set to page wide OR set by xml to larger then page wide
130
-		if ($this->width == 0 || $this->width > $renderer->getRemainingWidth()) {
131
-			$this->width = $renderer->getRemainingWidth();
132
-		}
133
-		// Setup the CellPadding
134
-		if ($this->padding) {
135
-			$cP = $renderer->cPadding;
136
-		}
129
+        // Check the width if set to page wide OR set by xml to larger then page wide
130
+        if ($this->width == 0 || $this->width > $renderer->getRemainingWidth()) {
131
+            $this->width = $renderer->getRemainingWidth();
132
+        }
133
+        // Setup the CellPadding
134
+        if ($this->padding) {
135
+            $cP = $renderer->cPadding;
136
+        }
137 137
 
138
-		// For padding, we have to use less wrap width
139
-		$cW = $this->width - ($cP * 2);
138
+        // For padding, we have to use less wrap width
139
+        $cW = $this->width - ($cP * 2);
140 140
 
141
-		//-- calculate the text box height
142
-		// Number of lines, will be converted to height
143
-		$cHT = 0;
144
-		// Element height (exept text)
145
-		$eH = 0;
146
-		// Footnote height (in points)
147
-		$fH = 0;
148
-		$w  = 0;
149
-		//-- $lw is an array
150
-		// 0 => last line width
151
-		// 1 => 1 if text was wrapped, 0 if text did not wrap
152
-		// 2 => number of LF
153
-		$lw = array();
154
-		// Element counter
155
-		$cE = count($this->elements);
156
-		for ($i = 0; $i < $cE; $i++) {
157
-			if (is_object($this->elements[$i])) {
158
-				$ew = $this->elements[$i]->setWrapWidth($cW - $w - 2, $cW);
159
-				if ($ew == $cW) {
160
-					$w = 0;
161
-				}
162
-				$lw = $this->elements[$i]->getWidth($renderer);
163
-				// Text is already gets the # LF
164
-				$cHT += $lw[2];
165
-				if ($lw[1] == 1) {
166
-					$w = $lw[0];
167
-				} elseif ($lw[1] == 2) {
168
-					$w = 0;
169
-				} else {
170
-					$w += $lw[0];
171
-				}
172
-				if ($w > $cW) {
173
-					$w = $lw[0];
174
-				}
175
-				// For anything else but text (images), get the height
176
-				$eH += $this->elements[$i]->getHeight($renderer);
177
-			} else {
178
-				$fH += abs($renderer->getFootnotesHeight($cW));
179
-			}
180
-		}
181
-		// Add up what’s the final height
182
-		$cH = $this->height;
183
-		// If any element exist
184
-		if ($cE > 0) {
185
-			// Check if this is text or some other element, like images
186
-			if ($eH == 0) {
187
-				// Number of LF but at least one line
188
-				$cHT = ($cHT + 1) * $renderer->cellHeightRatio;
189
-				// Calculate the cell hight with the largest font size used
190
-				$cHT = $cHT * $renderer->largestFontHeight;
191
-				if ($cH < $cHT) {
192
-					$cH = $cHT;
193
-				}
194
-			} // This is any other element
195
-			else {
196
-				if ($cH < $eH) {
197
-					$cH = $eH;
198
-				}
199
-				// Add Footnote height to the rest of the height
200
-				$cH += $fH;
201
-			}
202
-		}
141
+        //-- calculate the text box height
142
+        // Number of lines, will be converted to height
143
+        $cHT = 0;
144
+        // Element height (exept text)
145
+        $eH = 0;
146
+        // Footnote height (in points)
147
+        $fH = 0;
148
+        $w  = 0;
149
+        //-- $lw is an array
150
+        // 0 => last line width
151
+        // 1 => 1 if text was wrapped, 0 if text did not wrap
152
+        // 2 => number of LF
153
+        $lw = array();
154
+        // Element counter
155
+        $cE = count($this->elements);
156
+        for ($i = 0; $i < $cE; $i++) {
157
+            if (is_object($this->elements[$i])) {
158
+                $ew = $this->elements[$i]->setWrapWidth($cW - $w - 2, $cW);
159
+                if ($ew == $cW) {
160
+                    $w = 0;
161
+                }
162
+                $lw = $this->elements[$i]->getWidth($renderer);
163
+                // Text is already gets the # LF
164
+                $cHT += $lw[2];
165
+                if ($lw[1] == 1) {
166
+                    $w = $lw[0];
167
+                } elseif ($lw[1] == 2) {
168
+                    $w = 0;
169
+                } else {
170
+                    $w += $lw[0];
171
+                }
172
+                if ($w > $cW) {
173
+                    $w = $lw[0];
174
+                }
175
+                // For anything else but text (images), get the height
176
+                $eH += $this->elements[$i]->getHeight($renderer);
177
+            } else {
178
+                $fH += abs($renderer->getFootnotesHeight($cW));
179
+            }
180
+        }
181
+        // Add up what’s the final height
182
+        $cH = $this->height;
183
+        // If any element exist
184
+        if ($cE > 0) {
185
+            // Check if this is text or some other element, like images
186
+            if ($eH == 0) {
187
+                // Number of LF but at least one line
188
+                $cHT = ($cHT + 1) * $renderer->cellHeightRatio;
189
+                // Calculate the cell hight with the largest font size used
190
+                $cHT = $cHT * $renderer->largestFontHeight;
191
+                if ($cH < $cHT) {
192
+                    $cH = $cHT;
193
+                }
194
+            } // This is any other element
195
+            else {
196
+                if ($cH < $eH) {
197
+                    $cH = $eH;
198
+                }
199
+                // Add Footnote height to the rest of the height
200
+                $cH += $fH;
201
+            }
202
+        }
203 203
 
204
-		unset($lw, $cHT, $fH, $w);
204
+        unset($lw, $cHT, $fH, $w);
205 205
 
206
-		// Finaly, check the last cells height
207
-		if ($cH < $renderer->lastCellHeight) {
208
-			$cH = $renderer->lastCellHeight;
209
-		}
210
-		// Update max Y incase of a pagebreak
211
-		// We don't want to over write any images or other stuff
212
-		$renderer->addMaxY($this->top + $cH);
206
+        // Finaly, check the last cells height
207
+        if ($cH < $renderer->lastCellHeight) {
208
+            $cH = $renderer->lastCellHeight;
209
+        }
210
+        // Update max Y incase of a pagebreak
211
+        // We don't want to over write any images or other stuff
212
+        $renderer->addMaxY($this->top + $cH);
213 213
 
214
-		// Start to print HTML
215
-		echo "<div style=\"position:absolute;top:", $this->top, "pt;";
216
-		// LTR (left) or RTL (right)
217
-		echo $renderer->alignRTL, ":", $cX, "pt;";
218
-		// Background color
219
-		if ($this->fill) {
220
-			if (!empty($this->bgcolor)) {
221
-				echo " background-color:", $this->bgcolor, ";";
222
-			}
223
-		}
224
-		// Print padding only when it’s set
225
-		if ($this->padding) {
226
-			// Use Cell around padding to support RTL also
227
-			echo "padding:", $cP, "pt;";
228
-		}
229
-		// Border setup
230
-		if ($this->border) {
231
-			echo " border:solid black 1pt;";
232
-			echo "width:", ($this->width - 1 - ($cP * 2)), "pt;height:", $cH - 1, "pt;";
233
-		} else {
234
-			echo "width:", ($this->width - ($cP * 2)), "pt;height:", $cH, "pt;";
235
-		}
236
-		echo "\">";
214
+        // Start to print HTML
215
+        echo "<div style=\"position:absolute;top:", $this->top, "pt;";
216
+        // LTR (left) or RTL (right)
217
+        echo $renderer->alignRTL, ":", $cX, "pt;";
218
+        // Background color
219
+        if ($this->fill) {
220
+            if (!empty($this->bgcolor)) {
221
+                echo " background-color:", $this->bgcolor, ";";
222
+            }
223
+        }
224
+        // Print padding only when it’s set
225
+        if ($this->padding) {
226
+            // Use Cell around padding to support RTL also
227
+            echo "padding:", $cP, "pt;";
228
+        }
229
+        // Border setup
230
+        if ($this->border) {
231
+            echo " border:solid black 1pt;";
232
+            echo "width:", ($this->width - 1 - ($cP * 2)), "pt;height:", $cH - 1, "pt;";
233
+        } else {
234
+            echo "width:", ($this->width - ($cP * 2)), "pt;height:", $cH, "pt;";
235
+        }
236
+        echo "\">";
237 237
 
238
-		// Do a little "margin" trick before print
239
-		// to get the correct current position => "."
240
-		$cXT = $renderer->getX();
241
-		$cYT = $renderer->getY();
242
-		$renderer->setXy(0, 0);
238
+        // Do a little "margin" trick before print
239
+        // to get the correct current position => "."
240
+        $cXT = $renderer->getX();
241
+        $cYT = $renderer->getY();
242
+        $renderer->setXy(0, 0);
243 243
 
244
-		// Print the text elements
245
-		foreach ($this->elements as $element) {
246
-			if (is_object($element)) {
247
-				$element->render($renderer, $cX, false);
248
-			} elseif (is_string($element) && $element == "footnotetexts") {
249
-				$renderer->footnotes();
250
-			} elseif (is_string($element) && $element == "addpage") {
251
-				$renderer->addPage();
252
-			}
253
-		}
254
-		echo "</div>\n";
244
+        // Print the text elements
245
+        foreach ($this->elements as $element) {
246
+            if (is_object($element)) {
247
+                $element->render($renderer, $cX, false);
248
+            } elseif (is_string($element) && $element == "footnotetexts") {
249
+                $renderer->footnotes();
250
+            } elseif (is_string($element) && $element == "addpage") {
251
+                $renderer->addPage();
252
+            }
253
+        }
254
+        echo "</div>\n";
255 255
 
256
-		// Reset "margins"
257
-		$renderer->setXy($cXT, $cYT);
258
-		// This will be mostly used to trick the multiple images last height
259
-		if ($this->reseth) {
260
-			$cH = 0;
261
-		}
262
-		// New line and some clean up
263
-		if (!$this->newline) {
264
-			$renderer->setXy($cX + $this->width, $this->top);
265
-			$renderer->lastCellHeight = $cH;
266
-		} else {
267
-			$renderer->setXy(0, $this->top + $cH + ($cP * 2));
268
-			$renderer->lastCellHeight = 0;
269
-		}
270
-	}
256
+        // Reset "margins"
257
+        $renderer->setXy($cXT, $cYT);
258
+        // This will be mostly used to trick the multiple images last height
259
+        if ($this->reseth) {
260
+            $cH = 0;
261
+        }
262
+        // New line and some clean up
263
+        if (!$this->newline) {
264
+            $renderer->setXy($cX + $this->width, $this->top);
265
+            $renderer->lastCellHeight = $cH;
266
+        } else {
267
+            $renderer->setXy(0, $this->top + $cH + ($cP * 2));
268
+            $renderer->lastCellHeight = 0;
269
+        }
270
+    }
271 271
 }
Please login to merge, or discard this patch.
Braces   +4 added lines, -2 removed lines patch added patch discarded remove patch
@@ -18,13 +18,15 @@
 block discarded – undo
18 18
 /**
19 19
  * Class ReportHtmlTextbox
20 20
  */
21
-class ReportHtmlTextbox extends ReportBaseTextbox {
21
+class ReportHtmlTextbox extends ReportBaseTextbox
22
+{
22 23
 	/**
23 24
 	 * Render the elements.
24 25
 	 *
25 26
 	 * @param ReportHtml $renderer
26 27
 	 */
27
-	public function render($renderer) {
28
+	public function render($renderer)
29
+	{
28 30
 		// checkFootnote
29 31
 		$newelements      = array();
30 32
 		$lastelement      = array();
Please login to merge, or discard this patch.
app/Report/ReportBaseCell.php 2 patches
Indentation   +160 added lines, -160 removed lines patch added patch discarded remove patch
@@ -19,171 +19,171 @@
 block discarded – undo
19 19
  * Class ReportBaseCell
20 20
  */
21 21
 class ReportBaseCell extends ReportBaseElement {
22
-	/**
23
-	 * Allows to center or align the text. Possible values are:<ul><li>left or empty string: left align</li><li>center: center align</li><li>right: right align</li><li>justify: justification (default value when $ishtml=false)</li></ul>
24
-	 *
25
-	 * @var string
26
-	 */
27
-	public $align = "";
28
-	/**
29
-	 * Whether or not a border should be printed around this box. 0 = no border, 1 = border. Default is 0.
30
-	 * Or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
31
-	 *
32
-	 * @var mixed
33
-	 */
34
-	public $border;
35
-	/**
36
-	 * Border color in HTML code
37
-	 *
38
-	 * @var string
39
-	 */
40
-	public $bocolor;
41
-	/**
42
-	 * The HTML color code to fill the background of this cell.
43
-	 *
44
-	 * @var string
45
-	 */
46
-	public $bgcolor;
47
-	/**
48
-	 * Indicates if the cell background must be painted (1) or transparent (0). Default value: 1.
49
-	 * If no background color is set then it will not be painted
50
-	 *
51
-	 * @var int
52
-	 */
53
-	public $fill;
54
-	/**
55
-	 * Cell height DEFAULT 0 (expressed in points)
56
-	 * The starting height of this cell. If the text wraps the height will automatically be adjusted.
57
-	 *
58
-	 * @var int
59
-	 */
60
-	public $height;
61
-	/**
62
-	 * Left position in user units (X-position). Default is the current position
63
-	 *
64
-	 * @var mixed
65
-	 */
66
-	public $left;
67
-	/**
68
-	 * Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right [DEFAULT]</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>
69
-	 *
70
-	 * @var int
71
-	 */
72
-	public $newline;
73
-	/**
74
-	 * The name of the Style that should be used to render the text.
75
-	 *
76
-	 * @var string
77
-	 */
78
-	public $styleName;
79
-	/**
80
-	 * Stretch carachter mode: <ul><li>0 = disabled (default)</li><li>1 = horizontal scaling only if necessary</li><li>2 = forced horizontal scaling</li><li>3 = character spacing only if necessary</li><li>4 = forced character spacing</li></ul>
81
-	 *
82
-	 * @var int
83
-	 */
84
-	public $stretch;
85
-	/**
86
-	 * Text color in HTML code
87
-	 *
88
-	 * @var string
89
-	 */
90
-	public $tcolor;
91
-	/**
92
-	 * Top position in user units (Y-position). Default is the current position
93
-	 *
94
-	 * @var mixed
95
-	 */
96
-	public $top;
97
-	/**
98
-	 * URL address
99
-	 *
100
-	 * @var string
101
-	 */
102
-	public $url;
103
-	/**
104
-	 * Cell width DEFAULT 0 (expressed in points)
105
-	 * Setting the width to 0 will make it the width from the current location to the right margin.
106
-	 *
107
-	 * @var int
108
-	 */
109
-	public $width;
22
+    /**
23
+     * Allows to center or align the text. Possible values are:<ul><li>left or empty string: left align</li><li>center: center align</li><li>right: right align</li><li>justify: justification (default value when $ishtml=false)</li></ul>
24
+     *
25
+     * @var string
26
+     */
27
+    public $align = "";
28
+    /**
29
+     * Whether or not a border should be printed around this box. 0 = no border, 1 = border. Default is 0.
30
+     * Or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
31
+     *
32
+     * @var mixed
33
+     */
34
+    public $border;
35
+    /**
36
+     * Border color in HTML code
37
+     *
38
+     * @var string
39
+     */
40
+    public $bocolor;
41
+    /**
42
+     * The HTML color code to fill the background of this cell.
43
+     *
44
+     * @var string
45
+     */
46
+    public $bgcolor;
47
+    /**
48
+     * Indicates if the cell background must be painted (1) or transparent (0). Default value: 1.
49
+     * If no background color is set then it will not be painted
50
+     *
51
+     * @var int
52
+     */
53
+    public $fill;
54
+    /**
55
+     * Cell height DEFAULT 0 (expressed in points)
56
+     * The starting height of this cell. If the text wraps the height will automatically be adjusted.
57
+     *
58
+     * @var int
59
+     */
60
+    public $height;
61
+    /**
62
+     * Left position in user units (X-position). Default is the current position
63
+     *
64
+     * @var mixed
65
+     */
66
+    public $left;
67
+    /**
68
+     * Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right [DEFAULT]</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>
69
+     *
70
+     * @var int
71
+     */
72
+    public $newline;
73
+    /**
74
+     * The name of the Style that should be used to render the text.
75
+     *
76
+     * @var string
77
+     */
78
+    public $styleName;
79
+    /**
80
+     * Stretch carachter mode: <ul><li>0 = disabled (default)</li><li>1 = horizontal scaling only if necessary</li><li>2 = forced horizontal scaling</li><li>3 = character spacing only if necessary</li><li>4 = forced character spacing</li></ul>
81
+     *
82
+     * @var int
83
+     */
84
+    public $stretch;
85
+    /**
86
+     * Text color in HTML code
87
+     *
88
+     * @var string
89
+     */
90
+    public $tcolor;
91
+    /**
92
+     * Top position in user units (Y-position). Default is the current position
93
+     *
94
+     * @var mixed
95
+     */
96
+    public $top;
97
+    /**
98
+     * URL address
99
+     *
100
+     * @var string
101
+     */
102
+    public $url;
103
+    /**
104
+     * Cell width DEFAULT 0 (expressed in points)
105
+     * Setting the width to 0 will make it the width from the current location to the right margin.
106
+     *
107
+     * @var int
108
+     */
109
+    public $width;
110 110
 
111
-	/** @var int Unknown */
112
-	public $reseth;
111
+    /** @var int Unknown */
112
+    public $reseth;
113 113
 
114
-	/**
115
-	 * CELL - Element
116
-	 *
117
-	 * @param int    $width   cell width (expressed in points)
118
-	 * @param int    $height  cell height (expressed in points)
119
-	 * @param mixed  $border  Border style
120
-	 * @param string $align   Text alignement
121
-	 * @param string $bgcolor Background color code
122
-	 * @param string $style   The name of the text style
123
-	 * @param int    $ln      Indicates where the current position should go after the call
124
-	 * @param mixed  $top     Y-position
125
-	 * @param mixed  $left    X-position
126
-	 * @param int    $fill    Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
127
-	 * @param int $stretch Stretch carachter mode
128
-	 * @param string $bocolor Border color
129
-	 * @param string $tcolor  Text color
130
-	 * @param        $reseth
131
-	 */
132
-	public function __construct(
133
-		$width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth
134
-	) {
135
-		$this->align     = $align;
136
-		$this->border    = $border;
137
-		$this->bgcolor   = $bgcolor;
138
-		$this->bocolor   = $bocolor;
139
-		$this->fill      = $fill;
140
-		$this->height    = $height;
141
-		$this->left      = $left;
142
-		$this->newline   = $ln;
143
-		$this->styleName = $style;
144
-		$this->text      = "";
145
-		$this->tcolor    = $tcolor;
146
-		$this->top       = $top;
147
-		$this->url       = "";
148
-		$this->stretch   = $stretch;
149
-		$this->width     = $width;
150
-		$this->reseth    = $reseth;
114
+    /**
115
+     * CELL - Element
116
+     *
117
+     * @param int    $width   cell width (expressed in points)
118
+     * @param int    $height  cell height (expressed in points)
119
+     * @param mixed  $border  Border style
120
+     * @param string $align   Text alignement
121
+     * @param string $bgcolor Background color code
122
+     * @param string $style   The name of the text style
123
+     * @param int    $ln      Indicates where the current position should go after the call
124
+     * @param mixed  $top     Y-position
125
+     * @param mixed  $left    X-position
126
+     * @param int    $fill    Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
127
+     * @param int $stretch Stretch carachter mode
128
+     * @param string $bocolor Border color
129
+     * @param string $tcolor  Text color
130
+     * @param        $reseth
131
+     */
132
+    public function __construct(
133
+        $width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth
134
+    ) {
135
+        $this->align     = $align;
136
+        $this->border    = $border;
137
+        $this->bgcolor   = $bgcolor;
138
+        $this->bocolor   = $bocolor;
139
+        $this->fill      = $fill;
140
+        $this->height    = $height;
141
+        $this->left      = $left;
142
+        $this->newline   = $ln;
143
+        $this->styleName = $style;
144
+        $this->text      = "";
145
+        $this->tcolor    = $tcolor;
146
+        $this->top       = $top;
147
+        $this->url       = "";
148
+        $this->stretch   = $stretch;
149
+        $this->width     = $width;
150
+        $this->reseth    = $reseth;
151 151
 
152
-		return 0;
153
-	}
152
+        return 0;
153
+    }
154 154
 
155
-	/**
156
-	 * Get the cell height
157
-	 *
158
-	 * @param $renderer
159
-	 *
160
-	 * @return float
161
-	 */
162
-	public function getHeight($renderer) {
163
-		return $this->height;
164
-	}
155
+    /**
156
+     * Get the cell height
157
+     *
158
+     * @param $renderer
159
+     *
160
+     * @return float
161
+     */
162
+    public function getHeight($renderer) {
163
+        return $this->height;
164
+    }
165 165
 
166
-	/**
167
-	 * Sets the current cells URL
168
-	 *
169
-	 * @param string $url The URL address to save
170
-	 *
171
-	 * @return int
172
-	 */
173
-	public function setUrl($url) {
174
-		$this->url = $url;
166
+    /**
167
+     * Sets the current cells URL
168
+     *
169
+     * @param string $url The URL address to save
170
+     *
171
+     * @return int
172
+     */
173
+    public function setUrl($url) {
174
+        $this->url = $url;
175 175
 
176
-		return 0;
177
-	}
176
+        return 0;
177
+    }
178 178
 
179
-	/**
180
-	 * Get the cell width
181
-	 *
182
-	 * @param $renderer
183
-	 *
184
-	 * @return float
185
-	 */
186
-	public function getWidth($renderer) {
187
-		return $this->width;
188
-	}
179
+    /**
180
+     * Get the cell width
181
+     *
182
+     * @param $renderer
183
+     *
184
+     * @return float
185
+     */
186
+    public function getWidth($renderer) {
187
+        return $this->width;
188
+    }
189 189
 }
Please login to merge, or discard this patch.
Braces   +8 added lines, -4 removed lines patch added patch discarded remove patch
@@ -18,7 +18,8 @@  discard block
 block discarded – undo
18 18
 /**
19 19
  * Class ReportBaseCell
20 20
  */
21
-class ReportBaseCell extends ReportBaseElement {
21
+class ReportBaseCell extends ReportBaseElement
22
+{
22 23
 	/**
23 24
 	 * Allows to center or align the text. Possible values are:<ul><li>left or empty string: left align</li><li>center: center align</li><li>right: right align</li><li>justify: justification (default value when $ishtml=false)</li></ul>
24 25
 	 *
@@ -159,7 +160,8 @@  discard block
 block discarded – undo
159 160
 	 *
160 161
 	 * @return float
161 162
 	 */
162
-	public function getHeight($renderer) {
163
+	public function getHeight($renderer)
164
+	{
163 165
 		return $this->height;
164 166
 	}
165 167
 
@@ -170,7 +172,8 @@  discard block
 block discarded – undo
170 172
 	 *
171 173
 	 * @return int
172 174
 	 */
173
-	public function setUrl($url) {
175
+	public function setUrl($url)
176
+	{
174 177
 		$this->url = $url;
175 178
 
176 179
 		return 0;
@@ -183,7 +186,8 @@  discard block
 block discarded – undo
183 186
 	 *
184 187
 	 * @return float
185 188
 	 */
186
-	public function getWidth($renderer) {
189
+	public function getWidth($renderer)
190
+	{
187 191
 		return $this->width;
188 192
 	}
189 193
 }
Please login to merge, or discard this patch.
app/Report/ReportHtmlFootnote.php 2 patches
Indentation   +133 added lines, -133 removed lines patch added patch discarded remove patch
@@ -19,150 +19,150 @@
 block discarded – undo
19 19
  * class ReportHtmlFootnote
20 20
  */
21 21
 class ReportHtmlFootnote extends ReportBaseFootnote {
22
-	/**
23
-	 * HTML Footnotes number renderer
24
-	 *
25
-	 * @param ReportHtml $renderer
26
-	 */
27
-	public function render($renderer) {
28
-		$renderer->setCurrentStyle("footnotenum");
29
-		echo "<a href=\"#footnote", $this->num, "\"><sup>";
30
-		$renderer->write($renderer->entityRTL . $this->num);
31
-		echo "</sup></a>\n";
32
-	}
22
+    /**
23
+     * HTML Footnotes number renderer
24
+     *
25
+     * @param ReportHtml $renderer
26
+     */
27
+    public function render($renderer) {
28
+        $renderer->setCurrentStyle("footnotenum");
29
+        echo "<a href=\"#footnote", $this->num, "\"><sup>";
30
+        $renderer->write($renderer->entityRTL . $this->num);
31
+        echo "</sup></a>\n";
32
+    }
33 33
 
34
-	/**
35
-	 * Write the Footnote text
36
-	 * Uses style name "footnote" by default
37
-	 *
38
-	 * @param ReportHtml $html
39
-	 */
40
-	public function renderFootnote($html) {
34
+    /**
35
+     * Write the Footnote text
36
+     * Uses style name "footnote" by default
37
+     *
38
+     * @param ReportHtml $html
39
+     */
40
+    public function renderFootnote($html) {
41 41
 
42
-		if ($html->getCurrentStyle() != $this->styleName) {
43
-			$html->setCurrentStyle($this->styleName);
44
-		}
42
+        if ($html->getCurrentStyle() != $this->styleName) {
43
+            $html->setCurrentStyle($this->styleName);
44
+        }
45 45
 
46
-		$temptext = str_replace("#PAGENUM#", $html->pageNo(), $this->text);
47
-		// underline «title» part of Source item
48
-		$temptext = str_replace(array('«', '»'), array('<u>', '</u>'), $temptext);
49
-		echo "\n<div><a name=\"footnote", $this->num, "\"></a>";
50
-		$html->write($this->num . ". " . $temptext);
51
-		echo "</div>";
46
+        $temptext = str_replace("#PAGENUM#", $html->pageNo(), $this->text);
47
+        // underline «title» part of Source item
48
+        $temptext = str_replace(array('«', '»'), array('<u>', '</u>'), $temptext);
49
+        echo "\n<div><a name=\"footnote", $this->num, "\"></a>";
50
+        $html->write($this->num . ". " . $temptext);
51
+        echo "</div>";
52 52
 
53
-		$html->setXy(0, $html->getY() + $this->getFootnoteHeight($html));
54
-	}
53
+        $html->setXy(0, $html->getY() + $this->getFootnoteHeight($html));
54
+    }
55 55
 
56
-	/**
57
-	 * Calculates the Footnotes height
58
-	 *
59
-	 * @param ReportHtml $html
60
-	 * @param int        $cellWidth The width of the cell to use it for text wraping
61
-	 *
62
-	 * @return int       Footnote height in points
63
-	 */
64
-	public function getFootnoteHeight($html, $cellWidth = 0) {
65
-		if ($html->getCurrentStyle() != $this->styleName) {
66
-			$html->setCurrentStyle($this->styleName);
67
-		}
56
+    /**
57
+     * Calculates the Footnotes height
58
+     *
59
+     * @param ReportHtml $html
60
+     * @param int        $cellWidth The width of the cell to use it for text wraping
61
+     *
62
+     * @return int       Footnote height in points
63
+     */
64
+    public function getFootnoteHeight($html, $cellWidth = 0) {
65
+        if ($html->getCurrentStyle() != $this->styleName) {
66
+            $html->setCurrentStyle($this->styleName);
67
+        }
68 68
 
69
-		if ($cellWidth > 0) {
70
-			$this->text = $html->textWrap($this->text, $cellWidth);
71
-		}
72
-		$this->text = $this->text . "\n\n";
73
-		$ct         = substr_count($this->text, "\n");
74
-		$fsize      = $html->getCurrentStyleHeight();
69
+        if ($cellWidth > 0) {
70
+            $this->text = $html->textWrap($this->text, $cellWidth);
71
+        }
72
+        $this->text = $this->text . "\n\n";
73
+        $ct         = substr_count($this->text, "\n");
74
+        $fsize      = $html->getCurrentStyleHeight();
75 75
 
76
-		return ($fsize * $ct) * $html->cellHeightRatio;
77
-	}
76
+        return ($fsize * $ct) * $html->cellHeightRatio;
77
+    }
78 78
 
79
-	/**
80
-	 * Get the width of text
81
-	 * Breaks up a text into lines if needed
82
-	 *
83
-	 * @param ReportHtml $html
84
-	 *
85
-	 * @return array
86
-	 */
87
-	public function getWidth($html) {
88
-		// Setup the style name
89
-		$html->setCurrentStyle("footnotenum");
79
+    /**
80
+     * Get the width of text
81
+     * Breaks up a text into lines if needed
82
+     *
83
+     * @param ReportHtml $html
84
+     *
85
+     * @return array
86
+     */
87
+    public function getWidth($html) {
88
+        // Setup the style name
89
+        $html->setCurrentStyle("footnotenum");
90 90
 
91
-		// Check for the largest font size in the box
92
-		$fsize = $html->getCurrentStyleHeight();
93
-		if ($fsize > $html->largestFontHeight) {
94
-			$html->largestFontHeight = $fsize;
95
-		}
91
+        // Check for the largest font size in the box
92
+        $fsize = $html->getCurrentStyleHeight();
93
+        if ($fsize > $html->largestFontHeight) {
94
+            $html->largestFontHeight = $fsize;
95
+        }
96 96
 
97
-		// Returns the Object if already numbered else false
98
-		if (empty($this->num)) {
99
-			$html->checkFootnote($this);
100
-		}
97
+        // Returns the Object if already numbered else false
98
+        if (empty($this->num)) {
99
+            $html->checkFootnote($this);
100
+        }
101 101
 
102
-		// Get the line width for the text in points + a little margin
103
-		$lw = $html->getStringWidth($this->numText);
104
-		// Line Feed counter - Number of lines in the text
105
-		$lfct = $html->countLines($this->numText);
106
-		// If there is still remaining wrap width...
107
-		if ($this->wrapWidthRemaining > 0) {
108
-			// Check with line counter too!
109
-			if ($lw >= $this->wrapWidthRemaining || $lfct > 1) {
110
-				$newtext            = "";
111
-				$wrapWidthRemaining = $this->wrapWidthRemaining;
112
-				$lines              = explode("\n", $this->numText);
113
-				// Go throught the text line by line
114
-				foreach ($lines as $line) {
115
-					// Line width in points + a little margin
116
-					$lw = $html->getStringWidth($line);
117
-					// If the line has to be wraped
118
-					if ($lw > $wrapWidthRemaining) {
119
-						$words    = explode(" ", $line);
120
-						$addspace = count($words);
121
-						$lw       = 0;
122
-						foreach ($words as $word) {
123
-							$addspace--;
124
-							$lw += $html->getStringWidth($word . " ");
125
-							if ($lw <= $wrapWidthRemaining) {
126
-								$newtext .= $word;
127
-								if ($addspace != 0) {
128
-									$newtext .= " ";
129
-								}
130
-							} else {
131
-								$lw = $html->getStringWidth($word . " ");
132
-								$newtext .= "\n$word";
133
-								if ($addspace != 0) {
134
-									$newtext .= " ";
135
-								}
136
-								// Reset the wrap width to the cell width
137
-								$wrapWidthRemaining = $this->wrapWidthCell;
138
-							}
139
-						}
140
-					} else {
141
-						$newtext .= $line;
142
-					}
143
-					// Check the Line Feed counter
144
-					if ($lfct > 1) {
145
-						// Add a new line feed as long as it’s not the last line
146
-						$newtext .= "\n";
147
-						// Reset the line width
148
-						$lw = 0;
149
-						// Reset the wrap width to the cell width
150
-						$wrapWidthRemaining = $this->wrapWidthCell;
151
-					}
152
-					$lfct--;
153
-				}
154
-				$this->numText = $newtext;
155
-				$lfct          = substr_count($this->numText, "\n");
102
+        // Get the line width for the text in points + a little margin
103
+        $lw = $html->getStringWidth($this->numText);
104
+        // Line Feed counter - Number of lines in the text
105
+        $lfct = $html->countLines($this->numText);
106
+        // If there is still remaining wrap width...
107
+        if ($this->wrapWidthRemaining > 0) {
108
+            // Check with line counter too!
109
+            if ($lw >= $this->wrapWidthRemaining || $lfct > 1) {
110
+                $newtext            = "";
111
+                $wrapWidthRemaining = $this->wrapWidthRemaining;
112
+                $lines              = explode("\n", $this->numText);
113
+                // Go throught the text line by line
114
+                foreach ($lines as $line) {
115
+                    // Line width in points + a little margin
116
+                    $lw = $html->getStringWidth($line);
117
+                    // If the line has to be wraped
118
+                    if ($lw > $wrapWidthRemaining) {
119
+                        $words    = explode(" ", $line);
120
+                        $addspace = count($words);
121
+                        $lw       = 0;
122
+                        foreach ($words as $word) {
123
+                            $addspace--;
124
+                            $lw += $html->getStringWidth($word . " ");
125
+                            if ($lw <= $wrapWidthRemaining) {
126
+                                $newtext .= $word;
127
+                                if ($addspace != 0) {
128
+                                    $newtext .= " ";
129
+                                }
130
+                            } else {
131
+                                $lw = $html->getStringWidth($word . " ");
132
+                                $newtext .= "\n$word";
133
+                                if ($addspace != 0) {
134
+                                    $newtext .= " ";
135
+                                }
136
+                                // Reset the wrap width to the cell width
137
+                                $wrapWidthRemaining = $this->wrapWidthCell;
138
+                            }
139
+                        }
140
+                    } else {
141
+                        $newtext .= $line;
142
+                    }
143
+                    // Check the Line Feed counter
144
+                    if ($lfct > 1) {
145
+                        // Add a new line feed as long as it’s not the last line
146
+                        $newtext .= "\n";
147
+                        // Reset the line width
148
+                        $lw = 0;
149
+                        // Reset the wrap width to the cell width
150
+                        $wrapWidthRemaining = $this->wrapWidthCell;
151
+                    }
152
+                    $lfct--;
153
+                }
154
+                $this->numText = $newtext;
155
+                $lfct          = substr_count($this->numText, "\n");
156 156
 
157
-				return array($lw, 1, $lfct);
158
-			}
159
-		}
160
-		$l    = 0;
161
-		$lfct = substr_count($this->numText, "\n");
162
-		if ($lfct > 0) {
163
-			$l = 2;
164
-		}
157
+                return array($lw, 1, $lfct);
158
+            }
159
+        }
160
+        $l    = 0;
161
+        $lfct = substr_count($this->numText, "\n");
162
+        if ($lfct > 0) {
163
+            $l = 2;
164
+        }
165 165
 
166
-		return array($lw, $l, $lfct);
167
-	}
166
+        return array($lw, $l, $lfct);
167
+    }
168 168
 }
Please login to merge, or discard this patch.
Braces   +10 added lines, -5 removed lines patch added patch discarded remove patch
@@ -18,13 +18,15 @@  discard block
 block discarded – undo
18 18
 /**
19 19
  * class ReportHtmlFootnote
20 20
  */
21
-class ReportHtmlFootnote extends ReportBaseFootnote {
21
+class ReportHtmlFootnote extends ReportBaseFootnote
22
+{
22 23
 	/**
23 24
 	 * HTML Footnotes number renderer
24 25
 	 *
25 26
 	 * @param ReportHtml $renderer
26 27
 	 */
27
-	public function render($renderer) {
28
+	public function render($renderer)
29
+	{
28 30
 		$renderer->setCurrentStyle("footnotenum");
29 31
 		echo "<a href=\"#footnote", $this->num, "\"><sup>";
30 32
 		$renderer->write($renderer->entityRTL . $this->num);
@@ -37,7 +39,8 @@  discard block
 block discarded – undo
37 39
 	 *
38 40
 	 * @param ReportHtml $html
39 41
 	 */
40
-	public function renderFootnote($html) {
42
+	public function renderFootnote($html)
43
+	{
41 44
 
42 45
 		if ($html->getCurrentStyle() != $this->styleName) {
43 46
 			$html->setCurrentStyle($this->styleName);
@@ -61,7 +64,8 @@  discard block
 block discarded – undo
61 64
 	 *
62 65
 	 * @return int       Footnote height in points
63 66
 	 */
64
-	public function getFootnoteHeight($html, $cellWidth = 0) {
67
+	public function getFootnoteHeight($html, $cellWidth = 0)
68
+	{
65 69
 		if ($html->getCurrentStyle() != $this->styleName) {
66 70
 			$html->setCurrentStyle($this->styleName);
67 71
 		}
@@ -84,7 +88,8 @@  discard block
 block discarded – undo
84 88
 	 *
85 89
 	 * @return array
86 90
 	 */
87
-	public function getWidth($html) {
91
+	public function getWidth($html)
92
+	{
88 93
 		// Setup the style name
89 94
 		$html->setCurrentStyle("footnotenum");
90 95
 
Please login to merge, or discard this patch.
app/Report/ReportBaseTextbox.php 2 patches
Indentation   +126 added lines, -126 removed lines patch added patch discarded remove patch
@@ -19,140 +19,140 @@
 block discarded – undo
19 19
  * Class ReportBaseTextbox
20 20
  */
21 21
 class ReportBaseTextbox extends ReportBaseElement {
22
-	/**
23
-	 * Array of elements in the TextBox
24
-	 *
25
-	 * @var array
26
-	 */
27
-	public $elements = array();
22
+    /**
23
+     * Array of elements in the TextBox
24
+     *
25
+     * @var array
26
+     */
27
+    public $elements = array();
28 28
 
29
-	/**
30
-	 *  Background color in HTML code
31
-	 *
32
-	 * @var string
33
-	 */
34
-	public $bgcolor;
35
-	/**
36
-	 * Whether or not paint the background
37
-	 *
38
-	 * @var bool
39
-	 */
40
-	public $fill;
29
+    /**
30
+     *  Background color in HTML code
31
+     *
32
+     * @var string
33
+     */
34
+    public $bgcolor;
35
+    /**
36
+     * Whether or not paint the background
37
+     *
38
+     * @var bool
39
+     */
40
+    public $fill;
41 41
 
42
-	/**
43
-	 * Position the left corner of this box on the page(expressed in points). The default is the current position.
44
-	 *
45
-	 * @var mixed
46
-	 */
47
-	public $left;
48
-	/**
49
-	 * Position the top corner of this box on the page(expressed in points). the default is the current position
50
-	 *
51
-	 * @var mixed
52
-	 */
53
-	public $top;
54
-	/**
55
-	 * After this box is finished rendering, should the next section of text start immediately after the this box or should it start on a new line under this box. 0 = no new line, 1 = force new line. Default is 0
56
-	 *
57
-	 * @var bool
58
-	 */
59
-	public $newline;
42
+    /**
43
+     * Position the left corner of this box on the page(expressed in points). The default is the current position.
44
+     *
45
+     * @var mixed
46
+     */
47
+    public $left;
48
+    /**
49
+     * Position the top corner of this box on the page(expressed in points). the default is the current position
50
+     *
51
+     * @var mixed
52
+     */
53
+    public $top;
54
+    /**
55
+     * After this box is finished rendering, should the next section of text start immediately after the this box or should it start on a new line under this box. 0 = no new line, 1 = force new line. Default is 0
56
+     *
57
+     * @var bool
58
+     */
59
+    public $newline;
60 60
 
61
-	/** @var bool Unused? */
62
-	public $pagecheck;
61
+    /** @var bool Unused? */
62
+    public $pagecheck;
63 63
 
64
-	/** @var bool Whether to print a border */
65
-	public $border;
64
+    /** @var bool Whether to print a border */
65
+    public $border;
66 66
 
67
-	/**
68
-	 * Style of rendering
69
-	 *
70
-	 * <ul>
71
-	 * <li>D or empty string: Draw (default).</li>
72
-	 * <li>F: Fill.</li>
73
-	 * <li>DF or FD: Draw and fill.</li>
74
-	 * <li>CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).</li>
75
-	 *<li>CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).</li>
76
-	 * </ul>
77
-	 *
78
-	 * @var string
79
-	 */
80
-	public $style;
67
+    /**
68
+     * Style of rendering
69
+     *
70
+     * <ul>
71
+     * <li>D or empty string: Draw (default).</li>
72
+     * <li>F: Fill.</li>
73
+     * <li>DF or FD: Draw and fill.</li>
74
+     * <li>CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).</li>
75
+     *<li>CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).</li>
76
+     * </ul>
77
+     *
78
+     * @var string
79
+     */
80
+    public $style;
81 81
 
82
-	/**
83
-	 * @var array Border style of rectangle. Array with keys among the following:
84
-	 * <ul>
85
-	 * <li>all: Line style of all borders. Array like for {@link SetLineStyle SetLineStyle}.</li>
86
-	 * <li>L, T, R, B or combinations: Line style of left, top, right or bottom border. Array like for {@link SetLineStyle SetLineStyle}.</li>
87
-	 * </ul>
88
-	 * Not yet in use
89
-	 * var $borderstyle;
90
-	 */
82
+    /**
83
+     * @var array Border style of rectangle. Array with keys among the following:
84
+     * <ul>
85
+     * <li>all: Line style of all borders. Array like for {@link SetLineStyle SetLineStyle}.</li>
86
+     * <li>L, T, R, B or combinations: Line style of left, top, right or bottom border. Array like for {@link SetLineStyle SetLineStyle}.</li>
87
+     * </ul>
88
+     * Not yet in use
89
+     * var $borderstyle;
90
+     */
91 91
 
92
-	/**
93
-	 * The starting height of this cell. If the text wraps the height will automatically be adjusted
94
-	 *
95
-	 * @var float
96
-	 */
97
-	public $height;
98
-	/**
99
-	 * Setting the width to 0 will make it the width from the current location to the right margin
100
-	 *
101
-	 * @var float
102
-	 */
103
-	public $width;
104
-	/**
105
-	 * Use cell padding or not
106
-	 *
107
-	 * @var bool
108
-	 */
109
-	public $padding;
110
-	/**
111
-	 * Resets this box last height after it’s done
112
-	 */
113
-	public $reseth;
92
+    /**
93
+     * The starting height of this cell. If the text wraps the height will automatically be adjusted
94
+     *
95
+     * @var float
96
+     */
97
+    public $height;
98
+    /**
99
+     * Setting the width to 0 will make it the width from the current location to the right margin
100
+     *
101
+     * @var float
102
+     */
103
+    public $width;
104
+    /**
105
+     * Use cell padding or not
106
+     *
107
+     * @var bool
108
+     */
109
+    public $padding;
110
+    /**
111
+     * Resets this box last height after it’s done
112
+     */
113
+    public $reseth;
114 114
 
115
-	/**
116
-	 * TextBox - Element - Base
117
-	 *
118
-	 * @param float  $width   Text box width
119
-	 * @param float  $height  Text box height
120
-	 * @param bool   $border
121
-	 * @param string $bgcolor Background color code in HTML
122
-	 * @param bool   $newline
123
-	 * @param mixed  $left
124
-	 * @param mixed  $top
125
-	 * @param bool   $pagecheck
126
-	 * @param string $style
127
-	 * @param bool   $fill
128
-	 * @param bool   $padding
129
-	 * @param bool   $reseth
130
-	 */
131
-	public function __construct(
132
-		$width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth
133
-	) {
134
-		$this->border    = $border;
135
-		$this->bgcolor   = $bgcolor;
136
-		$this->fill      = $fill;
137
-		$this->height    = $height;
138
-		$this->left      = $left;
139
-		$this->newline   = $newline;
140
-		$this->pagecheck = $pagecheck;
141
-		$this->style     = $style;
142
-		$this->top       = $top;
143
-		$this->width     = $width;
144
-		$this->padding   = $padding;
145
-		$this->reseth    = $reseth;
115
+    /**
116
+     * TextBox - Element - Base
117
+     *
118
+     * @param float  $width   Text box width
119
+     * @param float  $height  Text box height
120
+     * @param bool   $border
121
+     * @param string $bgcolor Background color code in HTML
122
+     * @param bool   $newline
123
+     * @param mixed  $left
124
+     * @param mixed  $top
125
+     * @param bool   $pagecheck
126
+     * @param string $style
127
+     * @param bool   $fill
128
+     * @param bool   $padding
129
+     * @param bool   $reseth
130
+     */
131
+    public function __construct(
132
+        $width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth
133
+    ) {
134
+        $this->border    = $border;
135
+        $this->bgcolor   = $bgcolor;
136
+        $this->fill      = $fill;
137
+        $this->height    = $height;
138
+        $this->left      = $left;
139
+        $this->newline   = $newline;
140
+        $this->pagecheck = $pagecheck;
141
+        $this->style     = $style;
142
+        $this->top       = $top;
143
+        $this->width     = $width;
144
+        $this->padding   = $padding;
145
+        $this->reseth    = $reseth;
146 146
 
147
-		return 0;
148
-	}
147
+        return 0;
148
+    }
149 149
 
150
-	/**
151
-	 * Add an element to the TextBox
152
-	 *
153
-	 * @param object|string $element
154
-	 */
155
-	public function addElement($element) {
156
-		$this->elements[] = $element;
157
-	}
150
+    /**
151
+     * Add an element to the TextBox
152
+     *
153
+     * @param object|string $element
154
+     */
155
+    public function addElement($element) {
156
+        $this->elements[] = $element;
157
+    }
158 158
 }
Please login to merge, or discard this patch.
Braces   +4 added lines, -2 removed lines patch added patch discarded remove patch
@@ -18,7 +18,8 @@  discard block
 block discarded – undo
18 18
 /**
19 19
  * Class ReportBaseTextbox
20 20
  */
21
-class ReportBaseTextbox extends ReportBaseElement {
21
+class ReportBaseTextbox extends ReportBaseElement
22
+{
22 23
 	/**
23 24
 	 * Array of elements in the TextBox
24 25
 	 *
@@ -152,7 +153,8 @@  discard block
 block discarded – undo
152 153
 	 *
153 154
 	 * @param object|string $element
154 155
 	 */
155
-	public function addElement($element) {
156
+	public function addElement($element)
157
+	{
156 158
 		$this->elements[] = $element;
157 159
 	}
158 160
 }
Please login to merge, or discard this patch.
app/Report/ReportTcpdf.php 2 patches
Indentation   +373 added lines, -373 removed lines patch added patch discarded remove patch
@@ -23,377 +23,377 @@
 block discarded – undo
23 23
  * This class inherits from the TCPDF class and is used to generate the PDF document
24 24
  */
25 25
 class ReportTcpdf extends TCPDF {
26
-	/** @var ReportBaseElement[] Array of elements in the header */
27
-	public $headerElements = array();
28
-
29
-	/** @var ReportBaseElement[] Array of elements in the page header */
30
-	public $pageHeaderElements = array();
31
-
32
-	/** @var ReportBaseElement[] Array of elements in the footer */
33
-	public $footerElements = array();
34
-
35
-	/** @var ReportBaseElement[] Array of elements in the body */
36
-	public $bodyElements = array();
37
-
38
-	/** @var ReportBaseFootnote[] Array of elements in the footer notes */
39
-	public $printedfootnotes = array();
40
-
41
-	/** @var string Currently used style name */
42
-	public $currentStyle;
43
-
44
-	/** @var int The last cell height */
45
-	public $lastCellHeight = 0;
46
-
47
-	/** @var int The largest font size within a TextBox to calculate the height */
48
-	public $largestFontHeight = 0;
49
-
50
-	/** @var int The last pictures page number */
51
-	public $lastpicpage = 0;
52
-
53
-	/** @var ReportBase The current report. */
54
-	public $wt_report;
55
-
56
-	/**
57
-	 * PDF Header -PDF
58
-	 */
59
-	public function header() {
60
-		foreach ($this->headerElements as $element) {
61
-			if (is_object($element)) {
62
-				$element->render($this);
63
-			} elseif (is_string($element) && $element == "footnotetexts") {
64
-				$this->footnotes();
65
-			} elseif (is_string($element) && $element == "addpage") {
66
-				$this->newPage();
67
-			}
68
-		}
69
-		foreach ($this->pageHeaderElements as $element) {
70
-			if (is_object($element)) {
71
-				$element->render($this);
72
-			} elseif (is_string($element) && $element == "footnotetexts") {
73
-				$this->footnotes();
74
-			} elseif (is_string($element) && $element == "addpage") {
75
-				$this->newPage();
76
-			}
77
-		}
78
-	}
79
-
80
-	/**
81
-	 * PDF Body -PDF
82
-	 */
83
-	public function body() {
84
-		$this->AddPage();
85
-		foreach ($this->bodyElements as $key => $element) {
86
-			if (is_object($element)) {
87
-				$element->render($this);
88
-			} elseif (is_string($element) && $element == "footnotetexts") {
89
-				$this->footnotes();
90
-			} elseif (is_string($element) && $element == "addpage") {
91
-				$this->newPage();
92
-			}
93
-			// Delete used elements in hope to reduce 'some' memory usage
94
-			unset($this->bodyElements[$key]);
95
-		}
96
-	}
97
-
98
-	/**
99
-	 * PDF Footnotes -PDF
100
-	 */
101
-	public function footnotes() {
102
-		foreach ($this->printedfootnotes as $element) {
103
-			if (($this->GetY() + $element->getFootnoteHeight($this)) > $this->getPageHeight()) {
104
-				$this->AddPage();
105
-			}
106
-			$element->renderFootnote($this);
107
-			if ($this->GetY() > $this->getPageHeight()) {
108
-				$this->AddPage();
109
-			}
110
-		}
111
-	}
112
-
113
-	/**
114
-	 * PDF Footer -PDF
115
-	 */
116
-	public function footer() {
117
-		foreach ($this->footerElements as $element) {
118
-			if (is_object($element)) {
119
-				$element->render($this);
120
-			} elseif (is_string($element) && $element == "footnotetexts") {
121
-				$this->footnotes();
122
-			} elseif (is_string($element) && $element == "addpage") {
123
-				$this->newPage();
124
-			}
125
-		}
126
-	}
127
-
128
-	/**
129
-	 * Add an element to the Header -PDF
130
-	 *
131
-	 * @param object|string $element
132
-	 *
133
-	 * @return int The number of the Header elements
134
-	 */
135
-	public function addHeader($element) {
136
-		$this->headerElements[] = $element;
137
-
138
-		return count($this->headerElements) - 1;
139
-	}
140
-
141
-	/**
142
-	 * Add an element to the Page Header -PDF
143
-	 *
144
-	 * @param object|string $element
145
-	 *
146
-	 * @return int The number of the Page Header elements
147
-	 */
148
-	public function addPageHeader($element) {
149
-		$this->pageHeaderElements[] = $element;
150
-
151
-		return count($this->pageHeaderElements) - 1;
152
-	}
153
-
154
-	/**
155
-	 * Add an element to the Body -PDF
156
-	 *
157
-	 * @param object|string $element
158
-	 *
159
-	 * @return int The number of the Body elements
160
-	 */
161
-	public function addBody($element) {
162
-		$this->bodyElements[] = $element;
163
-
164
-		return count($this->bodyElements) - 1;
165
-	}
166
-
167
-	/**
168
-	 * Add an element to the Footer -PDF
169
-	 *
170
-	 * @param object|string $element
171
-	 *
172
-	 * @return int The number of the Footer elements
173
-	 */
174
-	public function addFooter($element) {
175
-		$this->footerElements[] = $element;
176
-
177
-		return count($this->footerElements) - 1;
178
-	}
179
-
180
-	/**
181
-	 * Remove the header.
182
-	 *
183
-	 * @param $index
184
-	 */
185
-	public function removeHeader($index) {
186
-		unset($this->headerElements[$index]);
187
-	}
188
-
189
-	/**
190
-	 * Remove the page header.
191
-	 *
192
-	 * @param $index
193
-	 */
194
-	public function removePageHeader($index) {
195
-		unset($this->pageHeaderElements[$index]);
196
-	}
197
-
198
-	/**
199
-	 * Remove the body.
200
-	 *
201
-	 * @param $index
202
-	 */
203
-	public function removeBody($index) {
204
-		unset($this->bodyElements[$index]);
205
-	}
206
-
207
-	/**
208
-	 * Remove the footer.
209
-	 *
210
-	 * @param $index
211
-	 */
212
-	public function removeFooter($index) {
213
-		unset($this->footerElements[$index]);
214
-	}
215
-
216
-	/**
217
-	 * Clear the Header -PDF
218
-	 */
219
-	public function clearHeader() {
220
-		unset($this->headerElements);
221
-		$this->headerElements = array();
222
-	}
223
-
224
-	/**
225
-	 * Clear the Page Header -PDF
226
-	 */
227
-	public function clearPageHeader() {
228
-		unset($this->pageHeaderElements);
229
-		$this->pageHeaderElements = array();
230
-	}
231
-
232
-	/**
233
-	 * Set the report.
234
-	 *
235
-	 * @param $r
236
-	 */
237
-	public function setReport($r) {
238
-		$this->wt_report = $r;
239
-	}
240
-
241
-	/**
242
-	 * Get the currently used style name -PDF
243
-	 *
244
-	 * @return string
245
-	 */
246
-	public function getCurrentStyle() {
247
-		return $this->currentStyle;
248
-	}
249
-
250
-	/**
251
-	 * Setup a style for usage -PDF
252
-	 *
253
-	 * @param string $s Style name
254
-	 */
255
-	public function setCurrentStyle($s) {
256
-		$this->currentStyle = $s;
257
-		$style              = $this->wt_report->getStyle($s);
258
-		$this->SetFont($style['font'], $style['style'], $style['size']);
259
-	}
260
-
261
-	/**
262
-	 * Get the style -PDF
263
-	 *
264
-	 * @param string $s Style name
265
-	 *
266
-	 * @return array
267
-	 */
268
-	public function getStyle($s) {
269
-		if (!isset($this->wt_report->Styles[$s])) {
270
-			$s                           = $this->getCurrentStyle();
271
-			$this->wt_report->Styles[$s] = $s;
272
-		}
273
-
274
-		return $this->wt_report->Styles[$s];
275
-	}
276
-
277
-	/**
278
-	 * Add margin when static horizontal position is used -PDF
279
-	 * RTL supported
280
-	 *
281
-	 * @param float $x Static position
282
-	 *
283
-	 * @return float
284
-	 */
285
-	public function addMarginX($x) {
286
-		$m = $this->getMargins();
287
-		if ($this->getRTL()) {
288
-			$x += $m['right'];
289
-		} else {
290
-			$x += $m['left'];
291
-		}
292
-		$this->SetX($x);
293
-
294
-		return $x;
295
-	}
296
-
297
-	/**
298
-	 * Get the maximum line width to draw from the curren position -PDF
299
-	 * RTL supported
300
-	 *
301
-	 * @return float
302
-	 */
303
-	public function getMaxLineWidth() {
304
-		$m = $this->getMargins();
305
-		if ($this->getRTL()) {
306
-			return ($this->getRemainingWidth() + $m['right']);
307
-		} else {
308
-			return ($this->getRemainingWidth() + $m['left']);
309
-		}
310
-	}
311
-
312
-	/**
313
-	 * Get the height of the footnote.
314
-	 *
315
-	 * @return int
316
-	 */
317
-	public function getFootnotesHeight() {
318
-		$h = 0;
319
-		foreach ($this->printedfootnotes as $element) {
320
-			$h += $element->getHeight($this);
321
-		}
322
-
323
-		return $h;
324
-	}
325
-
326
-	/**
327
-	 * Returns the the current font size height -PDF
328
-	 *
329
-	 * @return int
330
-	 */
331
-	public function getCurrentStyleHeight() {
332
-		if (empty($this->currentStyle)) {
333
-			return $this->wt_report->defaultFontSize;
334
-		}
335
-		$style = $this->wt_report->getStyle($this->currentStyle);
336
-
337
-		return $style['size'];
338
-	}
339
-
340
-	/**
341
-	 * Checks the Footnote and numbers them
342
-	 *
343
-	 * @param object $footnote
344
-	 *
345
-	 * @return bool false if not numbered befor | object if already numbered
346
-	 */
347
-	public function checkFootnote($footnote) {
348
-		$ct  = count($this->printedfootnotes);
349
-		$val = $footnote->getValue();
350
-		$i   = 0;
351
-		while ($i < $ct) {
352
-			if ($this->printedfootnotes[$i]->getValue() == $val) {
353
-				// If this footnote already exist then set up the numbers for this object
354
-				$footnote->setNum($i + 1);
355
-				$footnote->setAddlink($i + 1);
356
-
357
-				return $this->printedfootnotes[$i];
358
-			}
359
-			$i++;
360
-		}
361
-		// If this Footnote has not been set up yet
362
-		$footnote->setNum($ct + 1);
363
-		$footnote->setAddlink($this->AddLink());
364
-		$this->printedfootnotes[] = $footnote;
365
-
366
-		return false;
367
-	}
368
-
369
-	/**
370
-	 * Used this function instead of AddPage()
371
-	 * This function will make sure that images will not be overwritten
372
-	 */
373
-	public function newPage() {
374
-		if ($this->lastpicpage > $this->getPage()) {
375
-			$this->setPage($this->lastpicpage);
376
-		}
377
-		$this->AddPage();
378
-	}
379
-
380
-	/**
381
-	 * Add a page if needed -PDF
382
-	 *
383
-	 * @param int $height Cell height
384
-	 *
385
-	 * @return bool true in case of page break, false otherwise
386
-	 */
387
-	public function checkPageBreakPDF($height) {
388
-		return $this->checkPageBreak($height);
389
-	}
390
-
391
-	/**
392
-	 * Returns the remaining width between the current position and margins -PDF
393
-	 *
394
-	 * @return float Remaining width
395
-	 */
396
-	public function getRemainingWidthPDF() {
397
-		return $this->getRemainingWidth();
398
-	}
26
+    /** @var ReportBaseElement[] Array of elements in the header */
27
+    public $headerElements = array();
28
+
29
+    /** @var ReportBaseElement[] Array of elements in the page header */
30
+    public $pageHeaderElements = array();
31
+
32
+    /** @var ReportBaseElement[] Array of elements in the footer */
33
+    public $footerElements = array();
34
+
35
+    /** @var ReportBaseElement[] Array of elements in the body */
36
+    public $bodyElements = array();
37
+
38
+    /** @var ReportBaseFootnote[] Array of elements in the footer notes */
39
+    public $printedfootnotes = array();
40
+
41
+    /** @var string Currently used style name */
42
+    public $currentStyle;
43
+
44
+    /** @var int The last cell height */
45
+    public $lastCellHeight = 0;
46
+
47
+    /** @var int The largest font size within a TextBox to calculate the height */
48
+    public $largestFontHeight = 0;
49
+
50
+    /** @var int The last pictures page number */
51
+    public $lastpicpage = 0;
52
+
53
+    /** @var ReportBase The current report. */
54
+    public $wt_report;
55
+
56
+    /**
57
+     * PDF Header -PDF
58
+     */
59
+    public function header() {
60
+        foreach ($this->headerElements as $element) {
61
+            if (is_object($element)) {
62
+                $element->render($this);
63
+            } elseif (is_string($element) && $element == "footnotetexts") {
64
+                $this->footnotes();
65
+            } elseif (is_string($element) && $element == "addpage") {
66
+                $this->newPage();
67
+            }
68
+        }
69
+        foreach ($this->pageHeaderElements as $element) {
70
+            if (is_object($element)) {
71
+                $element->render($this);
72
+            } elseif (is_string($element) && $element == "footnotetexts") {
73
+                $this->footnotes();
74
+            } elseif (is_string($element) && $element == "addpage") {
75
+                $this->newPage();
76
+            }
77
+        }
78
+    }
79
+
80
+    /**
81
+     * PDF Body -PDF
82
+     */
83
+    public function body() {
84
+        $this->AddPage();
85
+        foreach ($this->bodyElements as $key => $element) {
86
+            if (is_object($element)) {
87
+                $element->render($this);
88
+            } elseif (is_string($element) && $element == "footnotetexts") {
89
+                $this->footnotes();
90
+            } elseif (is_string($element) && $element == "addpage") {
91
+                $this->newPage();
92
+            }
93
+            // Delete used elements in hope to reduce 'some' memory usage
94
+            unset($this->bodyElements[$key]);
95
+        }
96
+    }
97
+
98
+    /**
99
+     * PDF Footnotes -PDF
100
+     */
101
+    public function footnotes() {
102
+        foreach ($this->printedfootnotes as $element) {
103
+            if (($this->GetY() + $element->getFootnoteHeight($this)) > $this->getPageHeight()) {
104
+                $this->AddPage();
105
+            }
106
+            $element->renderFootnote($this);
107
+            if ($this->GetY() > $this->getPageHeight()) {
108
+                $this->AddPage();
109
+            }
110
+        }
111
+    }
112
+
113
+    /**
114
+     * PDF Footer -PDF
115
+     */
116
+    public function footer() {
117
+        foreach ($this->footerElements as $element) {
118
+            if (is_object($element)) {
119
+                $element->render($this);
120
+            } elseif (is_string($element) && $element == "footnotetexts") {
121
+                $this->footnotes();
122
+            } elseif (is_string($element) && $element == "addpage") {
123
+                $this->newPage();
124
+            }
125
+        }
126
+    }
127
+
128
+    /**
129
+     * Add an element to the Header -PDF
130
+     *
131
+     * @param object|string $element
132
+     *
133
+     * @return int The number of the Header elements
134
+     */
135
+    public function addHeader($element) {
136
+        $this->headerElements[] = $element;
137
+
138
+        return count($this->headerElements) - 1;
139
+    }
140
+
141
+    /**
142
+     * Add an element to the Page Header -PDF
143
+     *
144
+     * @param object|string $element
145
+     *
146
+     * @return int The number of the Page Header elements
147
+     */
148
+    public function addPageHeader($element) {
149
+        $this->pageHeaderElements[] = $element;
150
+
151
+        return count($this->pageHeaderElements) - 1;
152
+    }
153
+
154
+    /**
155
+     * Add an element to the Body -PDF
156
+     *
157
+     * @param object|string $element
158
+     *
159
+     * @return int The number of the Body elements
160
+     */
161
+    public function addBody($element) {
162
+        $this->bodyElements[] = $element;
163
+
164
+        return count($this->bodyElements) - 1;
165
+    }
166
+
167
+    /**
168
+     * Add an element to the Footer -PDF
169
+     *
170
+     * @param object|string $element
171
+     *
172
+     * @return int The number of the Footer elements
173
+     */
174
+    public function addFooter($element) {
175
+        $this->footerElements[] = $element;
176
+
177
+        return count($this->footerElements) - 1;
178
+    }
179
+
180
+    /**
181
+     * Remove the header.
182
+     *
183
+     * @param $index
184
+     */
185
+    public function removeHeader($index) {
186
+        unset($this->headerElements[$index]);
187
+    }
188
+
189
+    /**
190
+     * Remove the page header.
191
+     *
192
+     * @param $index
193
+     */
194
+    public function removePageHeader($index) {
195
+        unset($this->pageHeaderElements[$index]);
196
+    }
197
+
198
+    /**
199
+     * Remove the body.
200
+     *
201
+     * @param $index
202
+     */
203
+    public function removeBody($index) {
204
+        unset($this->bodyElements[$index]);
205
+    }
206
+
207
+    /**
208
+     * Remove the footer.
209
+     *
210
+     * @param $index
211
+     */
212
+    public function removeFooter($index) {
213
+        unset($this->footerElements[$index]);
214
+    }
215
+
216
+    /**
217
+     * Clear the Header -PDF
218
+     */
219
+    public function clearHeader() {
220
+        unset($this->headerElements);
221
+        $this->headerElements = array();
222
+    }
223
+
224
+    /**
225
+     * Clear the Page Header -PDF
226
+     */
227
+    public function clearPageHeader() {
228
+        unset($this->pageHeaderElements);
229
+        $this->pageHeaderElements = array();
230
+    }
231
+
232
+    /**
233
+     * Set the report.
234
+     *
235
+     * @param $r
236
+     */
237
+    public function setReport($r) {
238
+        $this->wt_report = $r;
239
+    }
240
+
241
+    /**
242
+     * Get the currently used style name -PDF
243
+     *
244
+     * @return string
245
+     */
246
+    public function getCurrentStyle() {
247
+        return $this->currentStyle;
248
+    }
249
+
250
+    /**
251
+     * Setup a style for usage -PDF
252
+     *
253
+     * @param string $s Style name
254
+     */
255
+    public function setCurrentStyle($s) {
256
+        $this->currentStyle = $s;
257
+        $style              = $this->wt_report->getStyle($s);
258
+        $this->SetFont($style['font'], $style['style'], $style['size']);
259
+    }
260
+
261
+    /**
262
+     * Get the style -PDF
263
+     *
264
+     * @param string $s Style name
265
+     *
266
+     * @return array
267
+     */
268
+    public function getStyle($s) {
269
+        if (!isset($this->wt_report->Styles[$s])) {
270
+            $s                           = $this->getCurrentStyle();
271
+            $this->wt_report->Styles[$s] = $s;
272
+        }
273
+
274
+        return $this->wt_report->Styles[$s];
275
+    }
276
+
277
+    /**
278
+     * Add margin when static horizontal position is used -PDF
279
+     * RTL supported
280
+     *
281
+     * @param float $x Static position
282
+     *
283
+     * @return float
284
+     */
285
+    public function addMarginX($x) {
286
+        $m = $this->getMargins();
287
+        if ($this->getRTL()) {
288
+            $x += $m['right'];
289
+        } else {
290
+            $x += $m['left'];
291
+        }
292
+        $this->SetX($x);
293
+
294
+        return $x;
295
+    }
296
+
297
+    /**
298
+     * Get the maximum line width to draw from the curren position -PDF
299
+     * RTL supported
300
+     *
301
+     * @return float
302
+     */
303
+    public function getMaxLineWidth() {
304
+        $m = $this->getMargins();
305
+        if ($this->getRTL()) {
306
+            return ($this->getRemainingWidth() + $m['right']);
307
+        } else {
308
+            return ($this->getRemainingWidth() + $m['left']);
309
+        }
310
+    }
311
+
312
+    /**
313
+     * Get the height of the footnote.
314
+     *
315
+     * @return int
316
+     */
317
+    public function getFootnotesHeight() {
318
+        $h = 0;
319
+        foreach ($this->printedfootnotes as $element) {
320
+            $h += $element->getHeight($this);
321
+        }
322
+
323
+        return $h;
324
+    }
325
+
326
+    /**
327
+     * Returns the the current font size height -PDF
328
+     *
329
+     * @return int
330
+     */
331
+    public function getCurrentStyleHeight() {
332
+        if (empty($this->currentStyle)) {
333
+            return $this->wt_report->defaultFontSize;
334
+        }
335
+        $style = $this->wt_report->getStyle($this->currentStyle);
336
+
337
+        return $style['size'];
338
+    }
339
+
340
+    /**
341
+     * Checks the Footnote and numbers them
342
+     *
343
+     * @param object $footnote
344
+     *
345
+     * @return bool false if not numbered befor | object if already numbered
346
+     */
347
+    public function checkFootnote($footnote) {
348
+        $ct  = count($this->printedfootnotes);
349
+        $val = $footnote->getValue();
350
+        $i   = 0;
351
+        while ($i < $ct) {
352
+            if ($this->printedfootnotes[$i]->getValue() == $val) {
353
+                // If this footnote already exist then set up the numbers for this object
354
+                $footnote->setNum($i + 1);
355
+                $footnote->setAddlink($i + 1);
356
+
357
+                return $this->printedfootnotes[$i];
358
+            }
359
+            $i++;
360
+        }
361
+        // If this Footnote has not been set up yet
362
+        $footnote->setNum($ct + 1);
363
+        $footnote->setAddlink($this->AddLink());
364
+        $this->printedfootnotes[] = $footnote;
365
+
366
+        return false;
367
+    }
368
+
369
+    /**
370
+     * Used this function instead of AddPage()
371
+     * This function will make sure that images will not be overwritten
372
+     */
373
+    public function newPage() {
374
+        if ($this->lastpicpage > $this->getPage()) {
375
+            $this->setPage($this->lastpicpage);
376
+        }
377
+        $this->AddPage();
378
+    }
379
+
380
+    /**
381
+     * Add a page if needed -PDF
382
+     *
383
+     * @param int $height Cell height
384
+     *
385
+     * @return bool true in case of page break, false otherwise
386
+     */
387
+    public function checkPageBreakPDF($height) {
388
+        return $this->checkPageBreak($height);
389
+    }
390
+
391
+    /**
392
+     * Returns the remaining width between the current position and margins -PDF
393
+     *
394
+     * @return float Remaining width
395
+     */
396
+    public function getRemainingWidthPDF() {
397
+        return $this->getRemainingWidth();
398
+    }
399 399
 }
Please login to merge, or discard this patch.
Braces   +54 added lines, -27 removed lines patch added patch discarded remove patch
@@ -22,7 +22,8 @@  discard block
 block discarded – undo
22 22
  *
23 23
  * This class inherits from the TCPDF class and is used to generate the PDF document
24 24
  */
25
-class ReportTcpdf extends TCPDF {
25
+class ReportTcpdf extends TCPDF
26
+{
26 27
 	/** @var ReportBaseElement[] Array of elements in the header */
27 28
 	public $headerElements = array();
28 29
 
@@ -56,7 +57,8 @@  discard block
 block discarded – undo
56 57
 	/**
57 58
 	 * PDF Header -PDF
58 59
 	 */
59
-	public function header() {
60
+	public function header()
61
+	{
60 62
 		foreach ($this->headerElements as $element) {
61 63
 			if (is_object($element)) {
62 64
 				$element->render($this);
@@ -80,7 +82,8 @@  discard block
 block discarded – undo
80 82
 	/**
81 83
 	 * PDF Body -PDF
82 84
 	 */
83
-	public function body() {
85
+	public function body()
86
+	{
84 87
 		$this->AddPage();
85 88
 		foreach ($this->bodyElements as $key => $element) {
86 89
 			if (is_object($element)) {
@@ -98,7 +101,8 @@  discard block
 block discarded – undo
98 101
 	/**
99 102
 	 * PDF Footnotes -PDF
100 103
 	 */
101
-	public function footnotes() {
104
+	public function footnotes()
105
+	{
102 106
 		foreach ($this->printedfootnotes as $element) {
103 107
 			if (($this->GetY() + $element->getFootnoteHeight($this)) > $this->getPageHeight()) {
104 108
 				$this->AddPage();
@@ -113,7 +117,8 @@  discard block
 block discarded – undo
113 117
 	/**
114 118
 	 * PDF Footer -PDF
115 119
 	 */
116
-	public function footer() {
120
+	public function footer()
121
+	{
117 122
 		foreach ($this->footerElements as $element) {
118 123
 			if (is_object($element)) {
119 124
 				$element->render($this);
@@ -132,7 +137,8 @@  discard block
 block discarded – undo
132 137
 	 *
133 138
 	 * @return int The number of the Header elements
134 139
 	 */
135
-	public function addHeader($element) {
140
+	public function addHeader($element)
141
+	{
136 142
 		$this->headerElements[] = $element;
137 143
 
138 144
 		return count($this->headerElements) - 1;
@@ -145,7 +151,8 @@  discard block
 block discarded – undo
145 151
 	 *
146 152
 	 * @return int The number of the Page Header elements
147 153
 	 */
148
-	public function addPageHeader($element) {
154
+	public function addPageHeader($element)
155
+	{
149 156
 		$this->pageHeaderElements[] = $element;
150 157
 
151 158
 		return count($this->pageHeaderElements) - 1;
@@ -158,7 +165,8 @@  discard block
 block discarded – undo
158 165
 	 *
159 166
 	 * @return int The number of the Body elements
160 167
 	 */
161
-	public function addBody($element) {
168
+	public function addBody($element)
169
+	{
162 170
 		$this->bodyElements[] = $element;
163 171
 
164 172
 		return count($this->bodyElements) - 1;
@@ -171,7 +179,8 @@  discard block
 block discarded – undo
171 179
 	 *
172 180
 	 * @return int The number of the Footer elements
173 181
 	 */
174
-	public function addFooter($element) {
182
+	public function addFooter($element)
183
+	{
175 184
 		$this->footerElements[] = $element;
176 185
 
177 186
 		return count($this->footerElements) - 1;
@@ -182,7 +191,8 @@  discard block
 block discarded – undo
182 191
 	 *
183 192
 	 * @param $index
184 193
 	 */
185
-	public function removeHeader($index) {
194
+	public function removeHeader($index)
195
+	{
186 196
 		unset($this->headerElements[$index]);
187 197
 	}
188 198
 
@@ -191,7 +201,8 @@  discard block
 block discarded – undo
191 201
 	 *
192 202
 	 * @param $index
193 203
 	 */
194
-	public function removePageHeader($index) {
204
+	public function removePageHeader($index)
205
+	{
195 206
 		unset($this->pageHeaderElements[$index]);
196 207
 	}
197 208
 
@@ -200,7 +211,8 @@  discard block
 block discarded – undo
200 211
 	 *
201 212
 	 * @param $index
202 213
 	 */
203
-	public function removeBody($index) {
214
+	public function removeBody($index)
215
+	{
204 216
 		unset($this->bodyElements[$index]);
205 217
 	}
206 218
 
@@ -209,14 +221,16 @@  discard block
 block discarded – undo
209 221
 	 *
210 222
 	 * @param $index
211 223
 	 */
212
-	public function removeFooter($index) {
224
+	public function removeFooter($index)
225
+	{
213 226
 		unset($this->footerElements[$index]);
214 227
 	}
215 228
 
216 229
 	/**
217 230
 	 * Clear the Header -PDF
218 231
 	 */
219
-	public function clearHeader() {
232
+	public function clearHeader()
233
+	{
220 234
 		unset($this->headerElements);
221 235
 		$this->headerElements = array();
222 236
 	}
@@ -224,7 +238,8 @@  discard block
 block discarded – undo
224 238
 	/**
225 239
 	 * Clear the Page Header -PDF
226 240
 	 */
227
-	public function clearPageHeader() {
241
+	public function clearPageHeader()
242
+	{
228 243
 		unset($this->pageHeaderElements);
229 244
 		$this->pageHeaderElements = array();
230 245
 	}
@@ -234,7 +249,8 @@  discard block
 block discarded – undo
234 249
 	 *
235 250
 	 * @param $r
236 251
 	 */
237
-	public function setReport($r) {
252
+	public function setReport($r)
253
+	{
238 254
 		$this->wt_report = $r;
239 255
 	}
240 256
 
@@ -243,7 +259,8 @@  discard block
 block discarded – undo
243 259
 	 *
244 260
 	 * @return string
245 261
 	 */
246
-	public function getCurrentStyle() {
262
+	public function getCurrentStyle()
263
+	{
247 264
 		return $this->currentStyle;
248 265
 	}
249 266
 
@@ -252,7 +269,8 @@  discard block
 block discarded – undo
252 269
 	 *
253 270
 	 * @param string $s Style name
254 271
 	 */
255
-	public function setCurrentStyle($s) {
272
+	public function setCurrentStyle($s)
273
+	{
256 274
 		$this->currentStyle = $s;
257 275
 		$style              = $this->wt_report->getStyle($s);
258 276
 		$this->SetFont($style['font'], $style['style'], $style['size']);
@@ -265,7 +283,8 @@  discard block
 block discarded – undo
265 283
 	 *
266 284
 	 * @return array
267 285
 	 */
268
-	public function getStyle($s) {
286
+	public function getStyle($s)
287
+	{
269 288
 		if (!isset($this->wt_report->Styles[$s])) {
270 289
 			$s                           = $this->getCurrentStyle();
271 290
 			$this->wt_report->Styles[$s] = $s;
@@ -282,7 +301,8 @@  discard block
 block discarded – undo
282 301
 	 *
283 302
 	 * @return float
284 303
 	 */
285
-	public function addMarginX($x) {
304
+	public function addMarginX($x)
305
+	{
286 306
 		$m = $this->getMargins();
287 307
 		if ($this->getRTL()) {
288 308
 			$x += $m['right'];
@@ -300,7 +320,8 @@  discard block
 block discarded – undo
300 320
 	 *
301 321
 	 * @return float
302 322
 	 */
303
-	public function getMaxLineWidth() {
323
+	public function getMaxLineWidth()
324
+	{
304 325
 		$m = $this->getMargins();
305 326
 		if ($this->getRTL()) {
306 327
 			return ($this->getRemainingWidth() + $m['right']);
@@ -314,7 +335,8 @@  discard block
 block discarded – undo
314 335
 	 *
315 336
 	 * @return int
316 337
 	 */
317
-	public function getFootnotesHeight() {
338
+	public function getFootnotesHeight()
339
+	{
318 340
 		$h = 0;
319 341
 		foreach ($this->printedfootnotes as $element) {
320 342
 			$h += $element->getHeight($this);
@@ -328,7 +350,8 @@  discard block
 block discarded – undo
328 350
 	 *
329 351
 	 * @return int
330 352
 	 */
331
-	public function getCurrentStyleHeight() {
353
+	public function getCurrentStyleHeight()
354
+	{
332 355
 		if (empty($this->currentStyle)) {
333 356
 			return $this->wt_report->defaultFontSize;
334 357
 		}
@@ -344,7 +367,8 @@  discard block
 block discarded – undo
344 367
 	 *
345 368
 	 * @return bool false if not numbered befor | object if already numbered
346 369
 	 */
347
-	public function checkFootnote($footnote) {
370
+	public function checkFootnote($footnote)
371
+	{
348 372
 		$ct  = count($this->printedfootnotes);
349 373
 		$val = $footnote->getValue();
350 374
 		$i   = 0;
@@ -370,7 +394,8 @@  discard block
 block discarded – undo
370 394
 	 * Used this function instead of AddPage()
371 395
 	 * This function will make sure that images will not be overwritten
372 396
 	 */
373
-	public function newPage() {
397
+	public function newPage()
398
+	{
374 399
 		if ($this->lastpicpage > $this->getPage()) {
375 400
 			$this->setPage($this->lastpicpage);
376 401
 		}
@@ -384,7 +409,8 @@  discard block
 block discarded – undo
384 409
 	 *
385 410
 	 * @return bool true in case of page break, false otherwise
386 411
 	 */
387
-	public function checkPageBreakPDF($height) {
412
+	public function checkPageBreakPDF($height)
413
+	{
388 414
 		return $this->checkPageBreak($height);
389 415
 	}
390 416
 
@@ -393,7 +419,8 @@  discard block
 block discarded – undo
393 419
 	 *
394 420
 	 * @return float Remaining width
395 421
 	 */
396
-	public function getRemainingWidthPDF() {
422
+	public function getRemainingWidthPDF()
423
+	{
397 424
 		return $this->getRemainingWidth();
398 425
 	}
399 426
 }
Please login to merge, or discard this patch.
app/Date.php 3 patches
Indentation   +548 added lines, -548 removed lines patch added patch discarded remove patch
@@ -37,552 +37,552 @@
 block discarded – undo
37 37
  * years or the OS/NS notation "4 FEB 1750/51".
38 38
  */
39 39
 class Date {
40
-	/** @var string Optional qualifier, such as BEF, FROM, ABT */
41
-	public $qual1;
42
-
43
-	/** @var CalendarDate  The first (or only) date */
44
-	private $date1;
45
-
46
-	/** @var string  Optional qualifier, such as TO, AND*/
47
-	public $qual2;
48
-
49
-	/** @var CalendarDate Optional second date */
50
-	private $date2;
51
-
52
-	/** @var string ptional text, as included with an INTerpreted date */
53
-	private $text;
54
-
55
-	/**
56
-	 * Create a date, from GEDCOM data.
57
-	 *
58
-	 * @param string $date A date in GEDCOM format
59
-	 */
60
-	public function __construct($date) {
61
-		// Extract any explanatory text
62
-		if (preg_match('/^(.*) ?[(](.*)[)]/', $date, $match)) {
63
-			$date       = $match[1];
64
-			$this->text = $match[2];
65
-		}
66
-		if (preg_match('/^(FROM|BET) (.+) (AND|TO) (.+)/', $date, $match)) {
67
-			$this->qual1 = $match[1];
68
-			$this->date1 = $this->parseDate($match[2]);
69
-			$this->qual2 = $match[3];
70
-			$this->date2 = $this->parseDate($match[4]);
71
-		} elseif (preg_match('/^(TO|FROM|BEF|AFT|CAL|EST|INT|ABT) (.+)/', $date, $match)) {
72
-			$this->qual1 = $match[1];
73
-			$this->date1 = $this->parseDate($match[2]);
74
-		} else {
75
-			$this->date1 = $this->parseDate($date);
76
-		}
77
-	}
78
-
79
-	/**
80
-	 * When we copy a date object, we need to create copies of
81
-	 * its child objects.
82
-	 */
83
-	public function __clone() {
84
-		$this->date1 = clone $this->date1;
85
-		if (is_object($this->date2)) {
86
-			$this->date2 = clone $this->date2;
87
-		}
88
-	}
89
-
90
-	/**
91
-	 * Convert a calendar date, such as "12 JUN 1943" into calendar date object.
92
-	 *
93
-	 * A GEDCOM date range may have two calendar dates.
94
-	 *
95
-	 * @param string $date
96
-	 *
97
-	 * @throws \DomainException
98
-	 *
99
-	 * @return CalendarDate
100
-	 */
101
-	private function parseDate($date) {
102
-		// Valid calendar escape specified? - use it
103
-		if (preg_match('/^(@#D(?:GREGORIAN|JULIAN|HEBREW|HIJRI|JALALI|FRENCH R|ROMAN)+@) ?(.*)/', $date, $match)) {
104
-			$cal  = $match[1];
105
-			$date = $match[2];
106
-		} else {
107
-			$cal = '';
108
-		}
109
-		// A date with a month: DM, M, MY or DMY
110
-		if (preg_match('/^(\d?\d?) ?(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|TSH|CSH|KSL|TVT|SHV|ADR|ADS|NSN|IYR|SVN|TMZ|AAV|ELL|VEND|BRUM|FRIM|NIVO|PLUV|VENT|GERM|FLOR|PRAI|MESS|THER|FRUC|COMP|MUHAR|SAFAR|RABI[AT]|JUMA[AT]|RAJAB|SHAAB|RAMAD|SHAWW|DHUAQ|DHUAH|FARVA|ORDIB|KHORD|TIR|MORDA|SHAHR|MEHR|ABAN|AZAR|DEY|BAHMA|ESFAN) ?((?:\d{1,4}(?: B\.C\.)?|\d\d\d\d\/\d\d)?)$/', $date, $match)) {
111
-			$d = $match[1];
112
-			$m = $match[2];
113
-			$y = $match[3];
114
-		} elseif (preg_match('/^(\d{1,4}(?: B\.C\.)?|\d\d\d\d\/\d\d)$/', $date, $match)) {
115
-				// A date with just a year
116
-				$d = '';
117
-				$m = '';
118
-				$y = $match[1];
119
-			} else {
120
-				// An invalid date - do the best we can.
121
-				$d = '';
122
-				$m = '';
123
-				$y = '';
124
-				// Look for a 3/4 digit year anywhere in the date
125
-				if (preg_match('/\b(\d{3,4})\b/', $date, $match)) {
126
-					$y = $match[1];
127
-				}
128
-				// Look for a month anywhere in the date
129
-				if (preg_match('/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|TSH|CSH|KSL|TVT|SHV|ADR|ADS|NSN|IYR|SVN|TMZ|AAV|ELL|VEND|BRUM|FRIM|NIVO|PLUV|VENT|GERM|FLOR|PRAI|MESS|THER|FRUC|COMP|MUHAR|SAFAR|RABI[AT]|JUMA[AT]|RAJAB|SHAAB|RAMAD|SHAWW|DHUAQ|DHUAH|FARVA|ORDIB|KHORD|TIR|MORDA|SHAHR|MEHR|ABAN|AZAR|DEY|BAHMA|ESFAN)/', $date, $match)) {
130
-					$m = $match[1];
131
-					// Look for a day number anywhere in the date
132
-					if (preg_match('/\b(\d\d?)\b/', $date, $match)) {
133
-						$d = $match[1];
134
-					}
135
-				}
136
-			}
137
-
138
-		// Unambiguous dates - override calendar escape
139
-		if (preg_match('/^(TSH|CSH|KSL|TVT|SHV|ADR|ADS|NSN|IYR|SVN|TMZ|AAV|ELL)$/', $m)) {
140
-			$cal = '@#DHEBREW@';
141
-		} else {
142
-			if (preg_match('/^(VEND|BRUM|FRIM|NIVO|PLUV|VENT|GERM|FLOR|PRAI|MESS|THER|FRUC|COMP)$/', $m)) {
143
-				$cal = '@#DFRENCH R@';
144
-			} else {
145
-				if (preg_match('/^(MUHAR|SAFAR|RABI[AT]|JUMA[AT]|RAJAB|SHAAB|RAMAD|SHAWW|DHUAQ|DHUAH)$/', $m)) {
146
-					$cal = '@#DHIJRI@'; // This is a WT extension
147
-				} else {
148
-					if (preg_match('/^(FARVA|ORDIB|KHORD|TIR|MORDA|SHAHR|MEHR|ABAN|AZAR|DEY|BAHMA|ESFAN)$/', $m)) {
149
-						$cal = '@#DJALALI@'; // This is a WT extension
150
-					} elseif (preg_match('/^\d{1,4}( B\.C\.)|\d\d\d\d\/\d\d$/', $y)) {
151
-						$cal = '@#DJULIAN@';
152
-					}
153
-				}
154
-			}
155
-		}
156
-
157
-		// Ambiguous dates - don't override calendar escape
158
-		if ($cal == '') {
159
-			if (preg_match('/^(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)$/', $m)) {
160
-				$cal = '@#DGREGORIAN@';
161
-			} else {
162
-				if (preg_match('/^[345]\d\d\d$/', $y)) {
163
-					// Year 3000-5999
164
-					$cal = '@#DHEBREW@';
165
-				} else {
166
-					$cal = '@#DGREGORIAN@';
167
-				}
168
-			}
169
-		}
170
-		// Now construct an object of the correct type
171
-		switch ($cal) {
172
-		case '@#DGREGORIAN@':
173
-			return new GregorianDate(array($y, $m, $d));
174
-		case '@#DJULIAN@':
175
-			return new JulianDate(array($y, $m, $d));
176
-		case '@#DHEBREW@':
177
-			return new JewishDate(array($y, $m, $d));
178
-		case '@#DHIJRI@':
179
-			return new HijriDate(array($y, $m, $d));
180
-		case '@#DFRENCH R@':
181
-			return new FrenchDate(array($y, $m, $d));
182
-		case '@#DJALALI@':
183
-			return new JalaliDate(array($y, $m, $d));
184
-		case '@#DROMAN@':
185
-			return new RomanDate(array($y, $m, $d));
186
-		default:
187
-			throw new \DomainException('Invalid calendar');
188
-		}
189
-	}
190
-
191
-	/**
192
-	 * A list of supported calendars and their names.
193
-	 *
194
-	 * @return string[]
195
-	 */
196
-	public static function calendarNames() {
197
-		return array(
198
-			'gregorian' => /* I18N: The gregorian calendar */ I18N::translate('Gregorian'),
199
-			'julian'    => /* I18N: The julian calendar */ I18N::translate('Julian'),
200
-			'french'    => /* I18N: The French calendar */ I18N::translate('French'),
201
-			'jewish'    => /* I18N: The Hebrew/Jewish calendar */ I18N::translate('Jewish'),
202
-			'hijri'     => /* I18N: The Arabic/Hijri calendar */ I18N::translate('Hijri'),
203
-			'jalali'    => /* I18N: The Persian/Jalali calendar */ I18N::translate('Jalali'),
204
-		);
205
-	}
206
-
207
-	/**
208
-	 * Convert a date to the preferred format and calendar(s) display.
209
-	 *
210
-	 * @param bool|null   $url               Wrap the date in a link to calendar.php
211
-	 * @param string|null $date_format       Override the default date format
212
-	 * @param bool|null   $convert_calendars Convert the date into other calendars
213
-	 *
214
-	 * @return string
215
-	 */
216
-	public function display($url = false, $date_format = null, $convert_calendars = true) {
217
-		global $WT_TREE;
218
-
219
-		$CALENDAR_FORMAT = $WT_TREE->getPreference('CALENDAR_FORMAT');
220
-
221
-		if ($date_format === null) {
222
-			$date_format = I18N::dateFormat();
223
-		}
224
-
225
-		if ($convert_calendars) {
226
-			$calendar_format = explode('_and_', $CALENDAR_FORMAT);
227
-		} else {
228
-			$calendar_format = array();
229
-		}
230
-
231
-		// Two dates with text before, between and after
232
-		$q1 = $this->qual1;
233
-		$d1 = $this->date1->format($date_format, $this->qual1);
234
-		$q2 = $this->qual2;
235
-		if (is_null($this->date2)) {
236
-			$d2 = '';
237
-		} else {
238
-			$d2 = $this->date2->format($date_format, $this->qual2);
239
-		}
240
-		// Con vert to other calendars, if requested
241
-		$conv1 = '';
242
-		$conv2 = '';
243
-		foreach ($calendar_format as $cal_fmt) {
244
-			if ($cal_fmt != 'none') {
245
-				$d1conv = $this->date1->convertToCalendar($cal_fmt);
246
-				if ($d1conv->inValidRange()) {
247
-					$d1tmp = $d1conv->format($date_format, $this->qual1);
248
-				} else {
249
-					$d1tmp = '';
250
-				}
251
-				if (is_null($this->date2)) {
252
-					$d2conv = null;
253
-					$d2tmp  = '';
254
-				} else {
255
-					$d2conv = $this->date2->convertToCalendar($cal_fmt);
256
-					if ($d2conv->inValidRange()) {
257
-						$d2tmp = $d2conv->format($date_format, $this->qual2);
258
-					} else {
259
-						$d2tmp = '';
260
-					}
261
-				}
262
-				// If the date is different from the unconverted date, add it to the date string.
263
-				if ($d1 != $d1tmp && $d1tmp !== '') {
264
-					if ($url) {
265
-						if ($CALENDAR_FORMAT !== 'none') {
266
-							$conv1 .= ' <span dir="' . I18N::direction() . '">(<a href="' . $d1conv->calendarUrl($date_format) . '" rel="nofollow">' . $d1tmp . '</a>)</span>';
267
-						} else {
268
-							$conv1 .= ' <span dir="' . I18N::direction() . '"><br><a href="' . $d1conv->calendarUrl($date_format) . '" rel="nofollow">' . $d1tmp . '</a></span>';
269
-						}
270
-					} else {
271
-						$conv1 .= ' <span dir="' . I18N::direction() . '">(' . $d1tmp . ')</span>';
272
-					}
273
-				}
274
-				if (!is_null($this->date2) && $d2 != $d2tmp && $d1tmp != '') {
275
-					if ($url) {
276
-						$conv2 .= ' <span dir="' . I18N::direction() . '">(<a href="' . $d2conv->calendarUrl($date_format) . '" rel="nofollow">' . $d2tmp . '</a>)</span>';
277
-					} else {
278
-						$conv2 .= ' <span dir="' . I18N::direction() . '">(' . $d2tmp . ')</span>';
279
-					}
280
-				}
281
-			}
282
-		}
283
-
284
-		// Add URLs, if requested
285
-		if ($url) {
286
-			$d1 = '<a href="' . $this->date1->calendarUrl($date_format) . '" rel="nofollow">' . $d1 . '</a>';
287
-			if (!is_null($this->date2)) {
288
-				$d2 = '<a href="' . $this->date2->calendarUrl($date_format) . '" rel="nofollow">' . $d2 . '</a>';
289
-			}
290
-		}
291
-
292
-		// Localise the date
293
-		switch ($q1 . $q2) {
294
-		case '':
295
-			$tmp = $d1 . $conv1;
296
-			break;
297
-		case 'ABT':
298
-			$tmp = /* I18N: Gedcom ABT dates */ I18N::translate('about %s', $d1 . $conv1);
299
-			break;
300
-		case 'CAL':
301
-			$tmp = /* I18N: Gedcom CAL dates */ I18N::translate('calculated %s', $d1 . $conv1);
302
-			break;
303
-		case 'EST':
304
-			$tmp = /* I18N: Gedcom EST dates */ I18N::translate('estimated %s', $d1 . $conv1);
305
-			break;
306
-		case 'INT':
307
-			$tmp = /* I18N: Gedcom INT dates */ I18N::translate('interpreted %s (%s)', $d1 . $conv1, Filter::escapeHtml($this->text));
308
-			break;
309
-		case 'BEF':
310
-			$tmp = /* I18N: Gedcom BEF dates */ I18N::translate('before %s', $d1 . $conv1);
311
-			break;
312
-		case 'AFT':
313
-			$tmp = /* I18N: Gedcom AFT dates */ I18N::translate('after %s', $d1 . $conv1);
314
-			break;
315
-		case 'FROM':
316
-			$tmp = /* I18N: Gedcom FROM dates */ I18N::translate('from %s', $d1 . $conv1);
317
-			break;
318
-		case 'TO':
319
-			$tmp = /* I18N: Gedcom TO dates */ I18N::translate('to %s', $d1 . $conv1);
320
-			break;
321
-		case 'BETAND':
322
-			$tmp = /* I18N: Gedcom BET-AND dates */ I18N::translate('between %s and %s', $d1 . $conv1, $d2 . $conv2);
323
-			break;
324
-		case 'FROMTO':
325
-			$tmp = /* I18N: Gedcom FROM-TO dates */ I18N::translate('from %s to %s', $d1 . $conv1, $d2 . $conv2);
326
-			break;
327
-		default:
328
-			$tmp = I18N::translate('Invalid date');
329
-			break; // e.g. BET without AND
330
-		}
331
-		if ($this->text && !$q1) {
332
-			$tmp = I18N::translate('%1$s (%2$s)', $tmp, $this->text);
333
-		}
334
-
335
-		if (strip_tags($tmp) === '') {
336
-			return '';
337
-		} else {
338
-			return '<span class="date">' . $tmp . '</span>';
339
-		}
340
-	}
341
-
342
-	/**
343
-	 * Get the earliest calendar date from this GEDCOM date.
344
-	 *
345
-	 * In the date “FROM 1900 TO 1910”, this would be 1900.
346
-	 *
347
-	 * @return CalendarDate
348
-	 */
349
-	public function minimumDate() {
350
-		return $this->date1;
351
-	}
352
-
353
-	/**
354
-	 * Get the latest calendar date from this GEDCOM date.
355
-	 *
356
-	 * In the date “FROM 1900 TO 1910”, this would be 1910.
357
-	 *
358
-	 * @return CalendarDate
359
-	 */
360
-	public function maximumDate() {
361
-		if (is_null($this->date2)) {
362
-			return $this->date1;
363
-		} else {
364
-			return $this->date2;
365
-		}
366
-	}
367
-
368
-	/**
369
-	 * Get the earliest Julian day number from this GEDCOM date.
370
-	 *
371
-	 * @return int
372
-	 */
373
-	public function minimumJulianDay() {
374
-		return $this->minimumDate()->minJD;
375
-	}
376
-
377
-	/**
378
-	 * Get the latest Julian day number from this GEDCOM date.
379
-	 *
380
-	 * @return int
381
-	 */
382
-	public function maximumJulianDay() {
383
-		return $this->maximumDate()->maxJD;
384
-	}
385
-
386
-	/**
387
-	 * Get the middle Julian day number from the GEDCOM date.
388
-	 *
389
-	 * For a month-only date, this would be somewhere around the 16th day.
390
-	 * For a year-only date, this would be somewhere around 1st July.
391
-	 *
392
-	 * @return int
393
-	 */
394
-	public function julianDay() {
395
-		return (int) (($this->minimumJulianDay() + $this->maximumJulianDay()) / 2);
396
-	}
397
-
398
-	/**
399
-	 * Offset this date by N years, and round to the whole year.
400
-	 *
401
-	 * This is typically used to create an estimated death date,
402
-	 * which is before a certain number of years after the birth date.
403
-	 *
404
-	 * @param int     $years     a number of years, positive or negative
405
-	 * @param string  $qualifier typically “BEF” or “AFT”
406
-	 *
407
-	 * @return Date
408
-	 */
409
-	public function addYears($years, $qualifier = '') {
410
-		$tmp = clone $this;
411
-		$tmp->date1->y += $years;
412
-		$tmp->date1->m = 0;
413
-		$tmp->date1->d = 0;
414
-		$tmp->date1->setJdFromYmd();
415
-		$tmp->qual1 = $qualifier;
416
-		$tmp->qual2 = '';
417
-		$tmp->date2 = null;
418
-
419
-		return $tmp;
420
-	}
421
-
422
-	/**
423
-	 * Calculate the the age of a person, on a date.
424
-	 *
425
-	 * @param Date $d1
426
-	 * @param Date $d2
427
-	 * @param int  $format
428
-	 *
429
-	 * @throws \InvalidArgumentException
430
-	 *
431
-	 * @return int|string
432
-	 */
433
-	public static function getAge(Date $d1, Date $d2 = null, $format = 0) {
434
-		if ($d2) {
435
-			if ($d2->maximumJulianDay() >= $d1->minimumJulianDay() && $d2->minimumJulianDay() <= $d1->minimumJulianDay()) {
436
-				// Overlapping dates
437
-				$jd = $d1->minimumJulianDay();
438
-			} else {
439
-				// Non-overlapping dates
440
-				$jd = $d2->minimumJulianDay();
441
-			}
442
-		} else {
443
-			// If second date not specified, use today’s date
444
-			$jd = WT_CLIENT_JD;
445
-		}
446
-
447
-		switch ($format) {
448
-		case 0:
449
-			// Years - integer only (for statistics, rather than for display)
450
-			if ($jd && $d1->minimumJulianDay() && $d1->minimumJulianDay() <= $jd) {
451
-				return $d1->minimumDate()->getAge(false, $jd, false);
452
-			} else {
453
-				return -1;
454
-			}
455
-		case 1:
456
-			// Days - integer only (for sorting, rather than for display)
457
-			if ($jd && $d1->minimumJulianDay()) {
458
-				return $jd - $d1->minimumJulianDay();
459
-			} else {
460
-				return -1;
461
-			}
462
-		case 2:
463
-			// Just years, in local digits, with warning for negative/
464
-			if ($jd && $d1->minimumJulianDay()) {
465
-				if ($d1->minimumJulianDay() > $jd) {
466
-					return '<i class="icon-warning"></i>';
467
-				} else {
468
-					return I18N::number($d1->minimumDate()->getAge(false, $jd));
469
-				}
470
-			} else {
471
-				return '';
472
-			}
473
-		default:
474
-			throw new \InvalidArgumentException('format: ' . $format);
475
-		}
476
-	}
477
-
478
-	/**
479
-	 * Calculate the years/months/days between two events
480
-	 * Return a gedcom style age string: "1y 2m 3d" (for fact details)
481
-	 *
482
-	 * @param Date      $d1
483
-	 * @param Date|null $d2
484
-	 *
485
-	 * @return string
486
-	 */
487
-	public static function getAgeGedcom(Date $d1, Date $d2 = null) {
488
-		if (is_null($d2)) {
489
-			return $d1->date1->getAge(true, WT_CLIENT_JD, true);
490
-		} else {
491
-			// If dates overlap, then can’t calculate age.
492
-			if (self::compare($d1, $d2)) {
493
-				return $d1->date1->getAge(true, $d2->minimumJulianDay(), true);
494
-			} elseif (self::compare($d1, $d2) == 0 && $d1->minimumJulianDay() == $d2->minimumJulianDay()) {
495
-				return '0d';
496
-			} else {
497
-				return '';
498
-			}
499
-		}
500
-	}
501
-
502
-	/**
503
-	 * Compare two dates, so they can be sorted.
504
-	 *
505
-	 * return <0 if $a<$b
506
-	 * return >0 if $b>$a
507
-	 * return  0 if dates same/overlap
508
-	 * BEF/AFT sort as the day before/after
509
-	 *
510
-	 * @param Date $a
511
-	 * @param Date $b
512
-	 *
513
-	 * @return int
514
-	 */
515
-	public static function compare(Date $a, Date $b) {
516
-		// Get min/max JD for each date.
517
-		switch ($a->qual1) {
518
-		case 'BEF':
519
-			$amin = $a->minimumJulianDay() - 1;
520
-			$amax = $amin;
521
-			break;
522
-		case 'AFT':
523
-			$amax = $a->maximumJulianDay() + 1;
524
-			$amin = $amax;
525
-			break;
526
-		default:
527
-			$amin = $a->minimumJulianDay();
528
-			$amax = $a->maximumJulianDay();
529
-			break;
530
-		}
531
-		switch ($b->qual1) {
532
-		case 'BEF':
533
-			$bmin = $b->minimumJulianDay() - 1;
534
-			$bmax = $bmin;
535
-			break;
536
-		case 'AFT':
537
-			$bmax = $b->maximumJulianDay() + 1;
538
-			$bmin = $bmax;
539
-			break;
540
-		default:
541
-			$bmin = $b->minimumJulianDay();
542
-			$bmax = $b->maximumJulianDay();
543
-			break;
544
-		}
545
-		if ($amax < $bmin) {
546
-			return -1;
547
-		} elseif ($amin > $bmax && $bmax > 0) {
548
-			return 1;
549
-		} elseif ($amin < $bmin && $amax <= $bmax) {
550
-			return -1;
551
-		} elseif ($amin > $bmin && $amax >= $bmax && $bmax > 0) {
552
-			return 1;
553
-		} else {
554
-			return 0;
555
-		}
556
-	}
557
-
558
-	/**
559
-	 * Check whether a gedcom date contains usable calendar date(s).
560
-	 *
561
-	 * An incomplete date such as "12 AUG" would be invalid, as
562
-	 * we cannot sort it.
563
-	 *
564
-	 * @return bool
565
-	 */
566
-	public function isOK() {
567
-		return $this->minimumJulianDay() && $this->maximumJulianDay();
568
-	}
569
-
570
-	/**
571
-	 * Calculate the gregorian year for a date. This should NOT be used internally
572
-	 * within WT - we should keep the code "calendar neutral" to allow support for
573
-	 * jewish/arabic users. This is only for interfacing with external entities,
574
-	 * such as the ancestry.com search interface or the dated fact icons.
575
-	 *
576
-	 * @return int
577
-	 */
578
-	public function gregorianYear() {
579
-		if ($this->isOK()) {
580
-			$gregorian_calendar = new GregorianCalendar;
581
-			list($year)         = $gregorian_calendar->jdToYmd($this->julianDay());
582
-
583
-			return $year;
584
-		} else {
585
-			return 0;
586
-		}
587
-	}
40
+    /** @var string Optional qualifier, such as BEF, FROM, ABT */
41
+    public $qual1;
42
+
43
+    /** @var CalendarDate  The first (or only) date */
44
+    private $date1;
45
+
46
+    /** @var string  Optional qualifier, such as TO, AND*/
47
+    public $qual2;
48
+
49
+    /** @var CalendarDate Optional second date */
50
+    private $date2;
51
+
52
+    /** @var string ptional text, as included with an INTerpreted date */
53
+    private $text;
54
+
55
+    /**
56
+     * Create a date, from GEDCOM data.
57
+     *
58
+     * @param string $date A date in GEDCOM format
59
+     */
60
+    public function __construct($date) {
61
+        // Extract any explanatory text
62
+        if (preg_match('/^(.*) ?[(](.*)[)]/', $date, $match)) {
63
+            $date       = $match[1];
64
+            $this->text = $match[2];
65
+        }
66
+        if (preg_match('/^(FROM|BET) (.+) (AND|TO) (.+)/', $date, $match)) {
67
+            $this->qual1 = $match[1];
68
+            $this->date1 = $this->parseDate($match[2]);
69
+            $this->qual2 = $match[3];
70
+            $this->date2 = $this->parseDate($match[4]);
71
+        } elseif (preg_match('/^(TO|FROM|BEF|AFT|CAL|EST|INT|ABT) (.+)/', $date, $match)) {
72
+            $this->qual1 = $match[1];
73
+            $this->date1 = $this->parseDate($match[2]);
74
+        } else {
75
+            $this->date1 = $this->parseDate($date);
76
+        }
77
+    }
78
+
79
+    /**
80
+     * When we copy a date object, we need to create copies of
81
+     * its child objects.
82
+     */
83
+    public function __clone() {
84
+        $this->date1 = clone $this->date1;
85
+        if (is_object($this->date2)) {
86
+            $this->date2 = clone $this->date2;
87
+        }
88
+    }
89
+
90
+    /**
91
+     * Convert a calendar date, such as "12 JUN 1943" into calendar date object.
92
+     *
93
+     * A GEDCOM date range may have two calendar dates.
94
+     *
95
+     * @param string $date
96
+     *
97
+     * @throws \DomainException
98
+     *
99
+     * @return CalendarDate
100
+     */
101
+    private function parseDate($date) {
102
+        // Valid calendar escape specified? - use it
103
+        if (preg_match('/^(@#D(?:GREGORIAN|JULIAN|HEBREW|HIJRI|JALALI|FRENCH R|ROMAN)+@) ?(.*)/', $date, $match)) {
104
+            $cal  = $match[1];
105
+            $date = $match[2];
106
+        } else {
107
+            $cal = '';
108
+        }
109
+        // A date with a month: DM, M, MY or DMY
110
+        if (preg_match('/^(\d?\d?) ?(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|TSH|CSH|KSL|TVT|SHV|ADR|ADS|NSN|IYR|SVN|TMZ|AAV|ELL|VEND|BRUM|FRIM|NIVO|PLUV|VENT|GERM|FLOR|PRAI|MESS|THER|FRUC|COMP|MUHAR|SAFAR|RABI[AT]|JUMA[AT]|RAJAB|SHAAB|RAMAD|SHAWW|DHUAQ|DHUAH|FARVA|ORDIB|KHORD|TIR|MORDA|SHAHR|MEHR|ABAN|AZAR|DEY|BAHMA|ESFAN) ?((?:\d{1,4}(?: B\.C\.)?|\d\d\d\d\/\d\d)?)$/', $date, $match)) {
111
+            $d = $match[1];
112
+            $m = $match[2];
113
+            $y = $match[3];
114
+        } elseif (preg_match('/^(\d{1,4}(?: B\.C\.)?|\d\d\d\d\/\d\d)$/', $date, $match)) {
115
+                // A date with just a year
116
+                $d = '';
117
+                $m = '';
118
+                $y = $match[1];
119
+            } else {
120
+                // An invalid date - do the best we can.
121
+                $d = '';
122
+                $m = '';
123
+                $y = '';
124
+                // Look for a 3/4 digit year anywhere in the date
125
+                if (preg_match('/\b(\d{3,4})\b/', $date, $match)) {
126
+                    $y = $match[1];
127
+                }
128
+                // Look for a month anywhere in the date
129
+                if (preg_match('/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|TSH|CSH|KSL|TVT|SHV|ADR|ADS|NSN|IYR|SVN|TMZ|AAV|ELL|VEND|BRUM|FRIM|NIVO|PLUV|VENT|GERM|FLOR|PRAI|MESS|THER|FRUC|COMP|MUHAR|SAFAR|RABI[AT]|JUMA[AT]|RAJAB|SHAAB|RAMAD|SHAWW|DHUAQ|DHUAH|FARVA|ORDIB|KHORD|TIR|MORDA|SHAHR|MEHR|ABAN|AZAR|DEY|BAHMA|ESFAN)/', $date, $match)) {
130
+                    $m = $match[1];
131
+                    // Look for a day number anywhere in the date
132
+                    if (preg_match('/\b(\d\d?)\b/', $date, $match)) {
133
+                        $d = $match[1];
134
+                    }
135
+                }
136
+            }
137
+
138
+        // Unambiguous dates - override calendar escape
139
+        if (preg_match('/^(TSH|CSH|KSL|TVT|SHV|ADR|ADS|NSN|IYR|SVN|TMZ|AAV|ELL)$/', $m)) {
140
+            $cal = '@#DHEBREW@';
141
+        } else {
142
+            if (preg_match('/^(VEND|BRUM|FRIM|NIVO|PLUV|VENT|GERM|FLOR|PRAI|MESS|THER|FRUC|COMP)$/', $m)) {
143
+                $cal = '@#DFRENCH R@';
144
+            } else {
145
+                if (preg_match('/^(MUHAR|SAFAR|RABI[AT]|JUMA[AT]|RAJAB|SHAAB|RAMAD|SHAWW|DHUAQ|DHUAH)$/', $m)) {
146
+                    $cal = '@#DHIJRI@'; // This is a WT extension
147
+                } else {
148
+                    if (preg_match('/^(FARVA|ORDIB|KHORD|TIR|MORDA|SHAHR|MEHR|ABAN|AZAR|DEY|BAHMA|ESFAN)$/', $m)) {
149
+                        $cal = '@#DJALALI@'; // This is a WT extension
150
+                    } elseif (preg_match('/^\d{1,4}( B\.C\.)|\d\d\d\d\/\d\d$/', $y)) {
151
+                        $cal = '@#DJULIAN@';
152
+                    }
153
+                }
154
+            }
155
+        }
156
+
157
+        // Ambiguous dates - don't override calendar escape
158
+        if ($cal == '') {
159
+            if (preg_match('/^(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)$/', $m)) {
160
+                $cal = '@#DGREGORIAN@';
161
+            } else {
162
+                if (preg_match('/^[345]\d\d\d$/', $y)) {
163
+                    // Year 3000-5999
164
+                    $cal = '@#DHEBREW@';
165
+                } else {
166
+                    $cal = '@#DGREGORIAN@';
167
+                }
168
+            }
169
+        }
170
+        // Now construct an object of the correct type
171
+        switch ($cal) {
172
+        case '@#DGREGORIAN@':
173
+            return new GregorianDate(array($y, $m, $d));
174
+        case '@#DJULIAN@':
175
+            return new JulianDate(array($y, $m, $d));
176
+        case '@#DHEBREW@':
177
+            return new JewishDate(array($y, $m, $d));
178
+        case '@#DHIJRI@':
179
+            return new HijriDate(array($y, $m, $d));
180
+        case '@#DFRENCH R@':
181
+            return new FrenchDate(array($y, $m, $d));
182
+        case '@#DJALALI@':
183
+            return new JalaliDate(array($y, $m, $d));
184
+        case '@#DROMAN@':
185
+            return new RomanDate(array($y, $m, $d));
186
+        default:
187
+            throw new \DomainException('Invalid calendar');
188
+        }
189
+    }
190
+
191
+    /**
192
+     * A list of supported calendars and their names.
193
+     *
194
+     * @return string[]
195
+     */
196
+    public static function calendarNames() {
197
+        return array(
198
+            'gregorian' => /* I18N: The gregorian calendar */ I18N::translate('Gregorian'),
199
+            'julian'    => /* I18N: The julian calendar */ I18N::translate('Julian'),
200
+            'french'    => /* I18N: The French calendar */ I18N::translate('French'),
201
+            'jewish'    => /* I18N: The Hebrew/Jewish calendar */ I18N::translate('Jewish'),
202
+            'hijri'     => /* I18N: The Arabic/Hijri calendar */ I18N::translate('Hijri'),
203
+            'jalali'    => /* I18N: The Persian/Jalali calendar */ I18N::translate('Jalali'),
204
+        );
205
+    }
206
+
207
+    /**
208
+     * Convert a date to the preferred format and calendar(s) display.
209
+     *
210
+     * @param bool|null   $url               Wrap the date in a link to calendar.php
211
+     * @param string|null $date_format       Override the default date format
212
+     * @param bool|null   $convert_calendars Convert the date into other calendars
213
+     *
214
+     * @return string
215
+     */
216
+    public function display($url = false, $date_format = null, $convert_calendars = true) {
217
+        global $WT_TREE;
218
+
219
+        $CALENDAR_FORMAT = $WT_TREE->getPreference('CALENDAR_FORMAT');
220
+
221
+        if ($date_format === null) {
222
+            $date_format = I18N::dateFormat();
223
+        }
224
+
225
+        if ($convert_calendars) {
226
+            $calendar_format = explode('_and_', $CALENDAR_FORMAT);
227
+        } else {
228
+            $calendar_format = array();
229
+        }
230
+
231
+        // Two dates with text before, between and after
232
+        $q1 = $this->qual1;
233
+        $d1 = $this->date1->format($date_format, $this->qual1);
234
+        $q2 = $this->qual2;
235
+        if (is_null($this->date2)) {
236
+            $d2 = '';
237
+        } else {
238
+            $d2 = $this->date2->format($date_format, $this->qual2);
239
+        }
240
+        // Con vert to other calendars, if requested
241
+        $conv1 = '';
242
+        $conv2 = '';
243
+        foreach ($calendar_format as $cal_fmt) {
244
+            if ($cal_fmt != 'none') {
245
+                $d1conv = $this->date1->convertToCalendar($cal_fmt);
246
+                if ($d1conv->inValidRange()) {
247
+                    $d1tmp = $d1conv->format($date_format, $this->qual1);
248
+                } else {
249
+                    $d1tmp = '';
250
+                }
251
+                if (is_null($this->date2)) {
252
+                    $d2conv = null;
253
+                    $d2tmp  = '';
254
+                } else {
255
+                    $d2conv = $this->date2->convertToCalendar($cal_fmt);
256
+                    if ($d2conv->inValidRange()) {
257
+                        $d2tmp = $d2conv->format($date_format, $this->qual2);
258
+                    } else {
259
+                        $d2tmp = '';
260
+                    }
261
+                }
262
+                // If the date is different from the unconverted date, add it to the date string.
263
+                if ($d1 != $d1tmp && $d1tmp !== '') {
264
+                    if ($url) {
265
+                        if ($CALENDAR_FORMAT !== 'none') {
266
+                            $conv1 .= ' <span dir="' . I18N::direction() . '">(<a href="' . $d1conv->calendarUrl($date_format) . '" rel="nofollow">' . $d1tmp . '</a>)</span>';
267
+                        } else {
268
+                            $conv1 .= ' <span dir="' . I18N::direction() . '"><br><a href="' . $d1conv->calendarUrl($date_format) . '" rel="nofollow">' . $d1tmp . '</a></span>';
269
+                        }
270
+                    } else {
271
+                        $conv1 .= ' <span dir="' . I18N::direction() . '">(' . $d1tmp . ')</span>';
272
+                    }
273
+                }
274
+                if (!is_null($this->date2) && $d2 != $d2tmp && $d1tmp != '') {
275
+                    if ($url) {
276
+                        $conv2 .= ' <span dir="' . I18N::direction() . '">(<a href="' . $d2conv->calendarUrl($date_format) . '" rel="nofollow">' . $d2tmp . '</a>)</span>';
277
+                    } else {
278
+                        $conv2 .= ' <span dir="' . I18N::direction() . '">(' . $d2tmp . ')</span>';
279
+                    }
280
+                }
281
+            }
282
+        }
283
+
284
+        // Add URLs, if requested
285
+        if ($url) {
286
+            $d1 = '<a href="' . $this->date1->calendarUrl($date_format) . '" rel="nofollow">' . $d1 . '</a>';
287
+            if (!is_null($this->date2)) {
288
+                $d2 = '<a href="' . $this->date2->calendarUrl($date_format) . '" rel="nofollow">' . $d2 . '</a>';
289
+            }
290
+        }
291
+
292
+        // Localise the date
293
+        switch ($q1 . $q2) {
294
+        case '':
295
+            $tmp = $d1 . $conv1;
296
+            break;
297
+        case 'ABT':
298
+            $tmp = /* I18N: Gedcom ABT dates */ I18N::translate('about %s', $d1 . $conv1);
299
+            break;
300
+        case 'CAL':
301
+            $tmp = /* I18N: Gedcom CAL dates */ I18N::translate('calculated %s', $d1 . $conv1);
302
+            break;
303
+        case 'EST':
304
+            $tmp = /* I18N: Gedcom EST dates */ I18N::translate('estimated %s', $d1 . $conv1);
305
+            break;
306
+        case 'INT':
307
+            $tmp = /* I18N: Gedcom INT dates */ I18N::translate('interpreted %s (%s)', $d1 . $conv1, Filter::escapeHtml($this->text));
308
+            break;
309
+        case 'BEF':
310
+            $tmp = /* I18N: Gedcom BEF dates */ I18N::translate('before %s', $d1 . $conv1);
311
+            break;
312
+        case 'AFT':
313
+            $tmp = /* I18N: Gedcom AFT dates */ I18N::translate('after %s', $d1 . $conv1);
314
+            break;
315
+        case 'FROM':
316
+            $tmp = /* I18N: Gedcom FROM dates */ I18N::translate('from %s', $d1 . $conv1);
317
+            break;
318
+        case 'TO':
319
+            $tmp = /* I18N: Gedcom TO dates */ I18N::translate('to %s', $d1 . $conv1);
320
+            break;
321
+        case 'BETAND':
322
+            $tmp = /* I18N: Gedcom BET-AND dates */ I18N::translate('between %s and %s', $d1 . $conv1, $d2 . $conv2);
323
+            break;
324
+        case 'FROMTO':
325
+            $tmp = /* I18N: Gedcom FROM-TO dates */ I18N::translate('from %s to %s', $d1 . $conv1, $d2 . $conv2);
326
+            break;
327
+        default:
328
+            $tmp = I18N::translate('Invalid date');
329
+            break; // e.g. BET without AND
330
+        }
331
+        if ($this->text && !$q1) {
332
+            $tmp = I18N::translate('%1$s (%2$s)', $tmp, $this->text);
333
+        }
334
+
335
+        if (strip_tags($tmp) === '') {
336
+            return '';
337
+        } else {
338
+            return '<span class="date">' . $tmp . '</span>';
339
+        }
340
+    }
341
+
342
+    /**
343
+     * Get the earliest calendar date from this GEDCOM date.
344
+     *
345
+     * In the date “FROM 1900 TO 1910”, this would be 1900.
346
+     *
347
+     * @return CalendarDate
348
+     */
349
+    public function minimumDate() {
350
+        return $this->date1;
351
+    }
352
+
353
+    /**
354
+     * Get the latest calendar date from this GEDCOM date.
355
+     *
356
+     * In the date “FROM 1900 TO 1910”, this would be 1910.
357
+     *
358
+     * @return CalendarDate
359
+     */
360
+    public function maximumDate() {
361
+        if (is_null($this->date2)) {
362
+            return $this->date1;
363
+        } else {
364
+            return $this->date2;
365
+        }
366
+    }
367
+
368
+    /**
369
+     * Get the earliest Julian day number from this GEDCOM date.
370
+     *
371
+     * @return int
372
+     */
373
+    public function minimumJulianDay() {
374
+        return $this->minimumDate()->minJD;
375
+    }
376
+
377
+    /**
378
+     * Get the latest Julian day number from this GEDCOM date.
379
+     *
380
+     * @return int
381
+     */
382
+    public function maximumJulianDay() {
383
+        return $this->maximumDate()->maxJD;
384
+    }
385
+
386
+    /**
387
+     * Get the middle Julian day number from the GEDCOM date.
388
+     *
389
+     * For a month-only date, this would be somewhere around the 16th day.
390
+     * For a year-only date, this would be somewhere around 1st July.
391
+     *
392
+     * @return int
393
+     */
394
+    public function julianDay() {
395
+        return (int) (($this->minimumJulianDay() + $this->maximumJulianDay()) / 2);
396
+    }
397
+
398
+    /**
399
+     * Offset this date by N years, and round to the whole year.
400
+     *
401
+     * This is typically used to create an estimated death date,
402
+     * which is before a certain number of years after the birth date.
403
+     *
404
+     * @param int     $years     a number of years, positive or negative
405
+     * @param string  $qualifier typically “BEF” or “AFT”
406
+     *
407
+     * @return Date
408
+     */
409
+    public function addYears($years, $qualifier = '') {
410
+        $tmp = clone $this;
411
+        $tmp->date1->y += $years;
412
+        $tmp->date1->m = 0;
413
+        $tmp->date1->d = 0;
414
+        $tmp->date1->setJdFromYmd();
415
+        $tmp->qual1 = $qualifier;
416
+        $tmp->qual2 = '';
417
+        $tmp->date2 = null;
418
+
419
+        return $tmp;
420
+    }
421
+
422
+    /**
423
+     * Calculate the the age of a person, on a date.
424
+     *
425
+     * @param Date $d1
426
+     * @param Date $d2
427
+     * @param int  $format
428
+     *
429
+     * @throws \InvalidArgumentException
430
+     *
431
+     * @return int|string
432
+     */
433
+    public static function getAge(Date $d1, Date $d2 = null, $format = 0) {
434
+        if ($d2) {
435
+            if ($d2->maximumJulianDay() >= $d1->minimumJulianDay() && $d2->minimumJulianDay() <= $d1->minimumJulianDay()) {
436
+                // Overlapping dates
437
+                $jd = $d1->minimumJulianDay();
438
+            } else {
439
+                // Non-overlapping dates
440
+                $jd = $d2->minimumJulianDay();
441
+            }
442
+        } else {
443
+            // If second date not specified, use today’s date
444
+            $jd = WT_CLIENT_JD;
445
+        }
446
+
447
+        switch ($format) {
448
+        case 0:
449
+            // Years - integer only (for statistics, rather than for display)
450
+            if ($jd && $d1->minimumJulianDay() && $d1->minimumJulianDay() <= $jd) {
451
+                return $d1->minimumDate()->getAge(false, $jd, false);
452
+            } else {
453
+                return -1;
454
+            }
455
+        case 1:
456
+            // Days - integer only (for sorting, rather than for display)
457
+            if ($jd && $d1->minimumJulianDay()) {
458
+                return $jd - $d1->minimumJulianDay();
459
+            } else {
460
+                return -1;
461
+            }
462
+        case 2:
463
+            // Just years, in local digits, with warning for negative/
464
+            if ($jd && $d1->minimumJulianDay()) {
465
+                if ($d1->minimumJulianDay() > $jd) {
466
+                    return '<i class="icon-warning"></i>';
467
+                } else {
468
+                    return I18N::number($d1->minimumDate()->getAge(false, $jd));
469
+                }
470
+            } else {
471
+                return '';
472
+            }
473
+        default:
474
+            throw new \InvalidArgumentException('format: ' . $format);
475
+        }
476
+    }
477
+
478
+    /**
479
+     * Calculate the years/months/days between two events
480
+     * Return a gedcom style age string: "1y 2m 3d" (for fact details)
481
+     *
482
+     * @param Date      $d1
483
+     * @param Date|null $d2
484
+     *
485
+     * @return string
486
+     */
487
+    public static function getAgeGedcom(Date $d1, Date $d2 = null) {
488
+        if (is_null($d2)) {
489
+            return $d1->date1->getAge(true, WT_CLIENT_JD, true);
490
+        } else {
491
+            // If dates overlap, then can’t calculate age.
492
+            if (self::compare($d1, $d2)) {
493
+                return $d1->date1->getAge(true, $d2->minimumJulianDay(), true);
494
+            } elseif (self::compare($d1, $d2) == 0 && $d1->minimumJulianDay() == $d2->minimumJulianDay()) {
495
+                return '0d';
496
+            } else {
497
+                return '';
498
+            }
499
+        }
500
+    }
501
+
502
+    /**
503
+     * Compare two dates, so they can be sorted.
504
+     *
505
+     * return <0 if $a<$b
506
+     * return >0 if $b>$a
507
+     * return  0 if dates same/overlap
508
+     * BEF/AFT sort as the day before/after
509
+     *
510
+     * @param Date $a
511
+     * @param Date $b
512
+     *
513
+     * @return int
514
+     */
515
+    public static function compare(Date $a, Date $b) {
516
+        // Get min/max JD for each date.
517
+        switch ($a->qual1) {
518
+        case 'BEF':
519
+            $amin = $a->minimumJulianDay() - 1;
520
+            $amax = $amin;
521
+            break;
522
+        case 'AFT':
523
+            $amax = $a->maximumJulianDay() + 1;
524
+            $amin = $amax;
525
+            break;
526
+        default:
527
+            $amin = $a->minimumJulianDay();
528
+            $amax = $a->maximumJulianDay();
529
+            break;
530
+        }
531
+        switch ($b->qual1) {
532
+        case 'BEF':
533
+            $bmin = $b->minimumJulianDay() - 1;
534
+            $bmax = $bmin;
535
+            break;
536
+        case 'AFT':
537
+            $bmax = $b->maximumJulianDay() + 1;
538
+            $bmin = $bmax;
539
+            break;
540
+        default:
541
+            $bmin = $b->minimumJulianDay();
542
+            $bmax = $b->maximumJulianDay();
543
+            break;
544
+        }
545
+        if ($amax < $bmin) {
546
+            return -1;
547
+        } elseif ($amin > $bmax && $bmax > 0) {
548
+            return 1;
549
+        } elseif ($amin < $bmin && $amax <= $bmax) {
550
+            return -1;
551
+        } elseif ($amin > $bmin && $amax >= $bmax && $bmax > 0) {
552
+            return 1;
553
+        } else {
554
+            return 0;
555
+        }
556
+    }
557
+
558
+    /**
559
+     * Check whether a gedcom date contains usable calendar date(s).
560
+     *
561
+     * An incomplete date such as "12 AUG" would be invalid, as
562
+     * we cannot sort it.
563
+     *
564
+     * @return bool
565
+     */
566
+    public function isOK() {
567
+        return $this->minimumJulianDay() && $this->maximumJulianDay();
568
+    }
569
+
570
+    /**
571
+     * Calculate the gregorian year for a date. This should NOT be used internally
572
+     * within WT - we should keep the code "calendar neutral" to allow support for
573
+     * jewish/arabic users. This is only for interfacing with external entities,
574
+     * such as the ancestry.com search interface or the dated fact icons.
575
+     *
576
+     * @return int
577
+     */
578
+    public function gregorianYear() {
579
+        if ($this->isOK()) {
580
+            $gregorian_calendar = new GregorianCalendar;
581
+            list($year)         = $gregorian_calendar->jdToYmd($this->julianDay());
582
+
583
+            return $year;
584
+        } else {
585
+            return 0;
586
+        }
587
+    }
588 588
 }
Please login to merge, or discard this patch.
Switch Indentation   +103 added lines, -103 removed lines patch added patch discarded remove patch
@@ -169,22 +169,22 @@  discard block
 block discarded – undo
169 169
 		}
170 170
 		// Now construct an object of the correct type
171 171
 		switch ($cal) {
172
-		case '@#DGREGORIAN@':
173
-			return new GregorianDate(array($y, $m, $d));
174
-		case '@#DJULIAN@':
175
-			return new JulianDate(array($y, $m, $d));
176
-		case '@#DHEBREW@':
177
-			return new JewishDate(array($y, $m, $d));
178
-		case '@#DHIJRI@':
179
-			return new HijriDate(array($y, $m, $d));
180
-		case '@#DFRENCH R@':
181
-			return new FrenchDate(array($y, $m, $d));
182
-		case '@#DJALALI@':
183
-			return new JalaliDate(array($y, $m, $d));
184
-		case '@#DROMAN@':
185
-			return new RomanDate(array($y, $m, $d));
186
-		default:
187
-			throw new \DomainException('Invalid calendar');
172
+		    case '@#DGREGORIAN@':
173
+			    return new GregorianDate(array($y, $m, $d));
174
+		    case '@#DJULIAN@':
175
+			    return new JulianDate(array($y, $m, $d));
176
+		    case '@#DHEBREW@':
177
+			    return new JewishDate(array($y, $m, $d));
178
+		    case '@#DHIJRI@':
179
+			    return new HijriDate(array($y, $m, $d));
180
+		    case '@#DFRENCH R@':
181
+			    return new FrenchDate(array($y, $m, $d));
182
+		    case '@#DJALALI@':
183
+			    return new JalaliDate(array($y, $m, $d));
184
+		    case '@#DROMAN@':
185
+			    return new RomanDate(array($y, $m, $d));
186
+		    default:
187
+			    throw new \DomainException('Invalid calendar');
188 188
 		}
189 189
 	}
190 190
 
@@ -291,42 +291,42 @@  discard block
 block discarded – undo
291 291
 
292 292
 		// Localise the date
293 293
 		switch ($q1 . $q2) {
294
-		case '':
295
-			$tmp = $d1 . $conv1;
296
-			break;
297
-		case 'ABT':
298
-			$tmp = /* I18N: Gedcom ABT dates */ I18N::translate('about %s', $d1 . $conv1);
299
-			break;
300
-		case 'CAL':
301
-			$tmp = /* I18N: Gedcom CAL dates */ I18N::translate('calculated %s', $d1 . $conv1);
302
-			break;
303
-		case 'EST':
304
-			$tmp = /* I18N: Gedcom EST dates */ I18N::translate('estimated %s', $d1 . $conv1);
305
-			break;
306
-		case 'INT':
307
-			$tmp = /* I18N: Gedcom INT dates */ I18N::translate('interpreted %s (%s)', $d1 . $conv1, Filter::escapeHtml($this->text));
308
-			break;
309
-		case 'BEF':
310
-			$tmp = /* I18N: Gedcom BEF dates */ I18N::translate('before %s', $d1 . $conv1);
311
-			break;
312
-		case 'AFT':
313
-			$tmp = /* I18N: Gedcom AFT dates */ I18N::translate('after %s', $d1 . $conv1);
314
-			break;
315
-		case 'FROM':
316
-			$tmp = /* I18N: Gedcom FROM dates */ I18N::translate('from %s', $d1 . $conv1);
317
-			break;
318
-		case 'TO':
319
-			$tmp = /* I18N: Gedcom TO dates */ I18N::translate('to %s', $d1 . $conv1);
320
-			break;
321
-		case 'BETAND':
322
-			$tmp = /* I18N: Gedcom BET-AND dates */ I18N::translate('between %s and %s', $d1 . $conv1, $d2 . $conv2);
323
-			break;
324
-		case 'FROMTO':
325
-			$tmp = /* I18N: Gedcom FROM-TO dates */ I18N::translate('from %s to %s', $d1 . $conv1, $d2 . $conv2);
326
-			break;
327
-		default:
328
-			$tmp = I18N::translate('Invalid date');
329
-			break; // e.g. BET without AND
294
+		    case '':
295
+			    $tmp = $d1 . $conv1;
296
+			    break;
297
+		    case 'ABT':
298
+			    $tmp = /* I18N: Gedcom ABT dates */ I18N::translate('about %s', $d1 . $conv1);
299
+			    break;
300
+		    case 'CAL':
301
+			    $tmp = /* I18N: Gedcom CAL dates */ I18N::translate('calculated %s', $d1 . $conv1);
302
+			    break;
303
+		    case 'EST':
304
+			    $tmp = /* I18N: Gedcom EST dates */ I18N::translate('estimated %s', $d1 . $conv1);
305
+			    break;
306
+		    case 'INT':
307
+			    $tmp = /* I18N: Gedcom INT dates */ I18N::translate('interpreted %s (%s)', $d1 . $conv1, Filter::escapeHtml($this->text));
308
+			    break;
309
+		    case 'BEF':
310
+			    $tmp = /* I18N: Gedcom BEF dates */ I18N::translate('before %s', $d1 . $conv1);
311
+			    break;
312
+		    case 'AFT':
313
+			    $tmp = /* I18N: Gedcom AFT dates */ I18N::translate('after %s', $d1 . $conv1);
314
+			    break;
315
+		    case 'FROM':
316
+			    $tmp = /* I18N: Gedcom FROM dates */ I18N::translate('from %s', $d1 . $conv1);
317
+			    break;
318
+		    case 'TO':
319
+			    $tmp = /* I18N: Gedcom TO dates */ I18N::translate('to %s', $d1 . $conv1);
320
+			    break;
321
+		    case 'BETAND':
322
+			    $tmp = /* I18N: Gedcom BET-AND dates */ I18N::translate('between %s and %s', $d1 . $conv1, $d2 . $conv2);
323
+			    break;
324
+		    case 'FROMTO':
325
+			    $tmp = /* I18N: Gedcom FROM-TO dates */ I18N::translate('from %s to %s', $d1 . $conv1, $d2 . $conv2);
326
+			    break;
327
+		    default:
328
+			    $tmp = I18N::translate('Invalid date');
329
+			    break; // e.g. BET without AND
330 330
 		}
331 331
 		if ($this->text && !$q1) {
332 332
 			$tmp = I18N::translate('%1$s (%2$s)', $tmp, $this->text);
@@ -445,33 +445,33 @@  discard block
 block discarded – undo
445 445
 		}
446 446
 
447 447
 		switch ($format) {
448
-		case 0:
449
-			// Years - integer only (for statistics, rather than for display)
450
-			if ($jd && $d1->minimumJulianDay() && $d1->minimumJulianDay() <= $jd) {
451
-				return $d1->minimumDate()->getAge(false, $jd, false);
452
-			} else {
453
-				return -1;
454
-			}
455
-		case 1:
456
-			// Days - integer only (for sorting, rather than for display)
457
-			if ($jd && $d1->minimumJulianDay()) {
458
-				return $jd - $d1->minimumJulianDay();
459
-			} else {
460
-				return -1;
461
-			}
462
-		case 2:
463
-			// Just years, in local digits, with warning for negative/
464
-			if ($jd && $d1->minimumJulianDay()) {
465
-				if ($d1->minimumJulianDay() > $jd) {
466
-					return '<i class="icon-warning"></i>';
467
-				} else {
468
-					return I18N::number($d1->minimumDate()->getAge(false, $jd));
469
-				}
470
-			} else {
471
-				return '';
472
-			}
473
-		default:
474
-			throw new \InvalidArgumentException('format: ' . $format);
448
+		    case 0:
449
+			    // Years - integer only (for statistics, rather than for display)
450
+			    if ($jd && $d1->minimumJulianDay() && $d1->minimumJulianDay() <= $jd) {
451
+				    return $d1->minimumDate()->getAge(false, $jd, false);
452
+			    } else {
453
+				    return -1;
454
+			    }
455
+		    case 1:
456
+			    // Days - integer only (for sorting, rather than for display)
457
+			    if ($jd && $d1->minimumJulianDay()) {
458
+				    return $jd - $d1->minimumJulianDay();
459
+			    } else {
460
+				    return -1;
461
+			    }
462
+		    case 2:
463
+			    // Just years, in local digits, with warning for negative/
464
+			    if ($jd && $d1->minimumJulianDay()) {
465
+				    if ($d1->minimumJulianDay() > $jd) {
466
+					    return '<i class="icon-warning"></i>';
467
+				    } else {
468
+					    return I18N::number($d1->minimumDate()->getAge(false, $jd));
469
+				    }
470
+			    } else {
471
+				    return '';
472
+			    }
473
+		    default:
474
+			    throw new \InvalidArgumentException('format: ' . $format);
475 475
 		}
476 476
 	}
477 477
 
@@ -515,32 +515,32 @@  discard block
 block discarded – undo
515 515
 	public static function compare(Date $a, Date $b) {
516 516
 		// Get min/max JD for each date.
517 517
 		switch ($a->qual1) {
518
-		case 'BEF':
519
-			$amin = $a->minimumJulianDay() - 1;
520
-			$amax = $amin;
521
-			break;
522
-		case 'AFT':
523
-			$amax = $a->maximumJulianDay() + 1;
524
-			$amin = $amax;
525
-			break;
526
-		default:
527
-			$amin = $a->minimumJulianDay();
528
-			$amax = $a->maximumJulianDay();
529
-			break;
518
+		    case 'BEF':
519
+			    $amin = $a->minimumJulianDay() - 1;
520
+			    $amax = $amin;
521
+			    break;
522
+		    case 'AFT':
523
+			    $amax = $a->maximumJulianDay() + 1;
524
+			    $amin = $amax;
525
+			    break;
526
+		    default:
527
+			    $amin = $a->minimumJulianDay();
528
+			    $amax = $a->maximumJulianDay();
529
+			    break;
530 530
 		}
531 531
 		switch ($b->qual1) {
532
-		case 'BEF':
533
-			$bmin = $b->minimumJulianDay() - 1;
534
-			$bmax = $bmin;
535
-			break;
536
-		case 'AFT':
537
-			$bmax = $b->maximumJulianDay() + 1;
538
-			$bmin = $bmax;
539
-			break;
540
-		default:
541
-			$bmin = $b->minimumJulianDay();
542
-			$bmax = $b->maximumJulianDay();
543
-			break;
532
+		    case 'BEF':
533
+			    $bmin = $b->minimumJulianDay() - 1;
534
+			    $bmax = $bmin;
535
+			    break;
536
+		    case 'AFT':
537
+			    $bmax = $b->maximumJulianDay() + 1;
538
+			    $bmin = $bmax;
539
+			    break;
540
+		    default:
541
+			    $bmin = $b->minimumJulianDay();
542
+			    $bmax = $b->maximumJulianDay();
543
+			    break;
544 544
 		}
545 545
 		if ($amax < $bmin) {
546 546
 			return -1;
Please login to merge, or discard this patch.
Braces   +34 added lines, -17 removed lines patch added patch discarded remove patch
@@ -36,7 +36,8 @@  discard block
 block discarded – undo
36 36
  * this is not the case (e.g. England prior to 1752), we need to use modified
37 37
  * years or the OS/NS notation "4 FEB 1750/51".
38 38
  */
39
-class Date {
39
+class Date
40
+{
40 41
 	/** @var string Optional qualifier, such as BEF, FROM, ABT */
41 42
 	public $qual1;
42 43
 
@@ -57,7 +58,8 @@  discard block
 block discarded – undo
57 58
 	 *
58 59
 	 * @param string $date A date in GEDCOM format
59 60
 	 */
60
-	public function __construct($date) {
61
+	public function __construct($date)
62
+	{
61 63
 		// Extract any explanatory text
62 64
 		if (preg_match('/^(.*) ?[(](.*)[)]/', $date, $match)) {
63 65
 			$date       = $match[1];
@@ -80,7 +82,8 @@  discard block
 block discarded – undo
80 82
 	 * When we copy a date object, we need to create copies of
81 83
 	 * its child objects.
82 84
 	 */
83
-	public function __clone() {
85
+	public function __clone()
86
+	{
84 87
 		$this->date1 = clone $this->date1;
85 88
 		if (is_object($this->date2)) {
86 89
 			$this->date2 = clone $this->date2;
@@ -98,7 +101,8 @@  discard block
 block discarded – undo
98 101
 	 *
99 102
 	 * @return CalendarDate
100 103
 	 */
101
-	private function parseDate($date) {
104
+	private function parseDate($date)
105
+	{
102 106
 		// Valid calendar escape specified? - use it
103 107
 		if (preg_match('/^(@#D(?:GREGORIAN|JULIAN|HEBREW|HIJRI|JALALI|FRENCH R|ROMAN)+@) ?(.*)/', $date, $match)) {
104 108
 			$cal  = $match[1];
@@ -193,7 +197,8 @@  discard block
 block discarded – undo
193 197
 	 *
194 198
 	 * @return string[]
195 199
 	 */
196
-	public static function calendarNames() {
200
+	public static function calendarNames()
201
+	{
197 202
 		return array(
198 203
 			'gregorian' => /* I18N: The gregorian calendar */ I18N::translate('Gregorian'),
199 204
 			'julian'    => /* I18N: The julian calendar */ I18N::translate('Julian'),
@@ -213,7 +218,8 @@  discard block
 block discarded – undo
213 218
 	 *
214 219
 	 * @return string
215 220
 	 */
216
-	public function display($url = false, $date_format = null, $convert_calendars = true) {
221
+	public function display($url = false, $date_format = null, $convert_calendars = true)
222
+	{
217 223
 		global $WT_TREE;
218 224
 
219 225
 		$CALENDAR_FORMAT = $WT_TREE->getPreference('CALENDAR_FORMAT');
@@ -346,7 +352,8 @@  discard block
 block discarded – undo
346 352
 	 *
347 353
 	 * @return CalendarDate
348 354
 	 */
349
-	public function minimumDate() {
355
+	public function minimumDate()
356
+	{
350 357
 		return $this->date1;
351 358
 	}
352 359
 
@@ -357,7 +364,8 @@  discard block
 block discarded – undo
357 364
 	 *
358 365
 	 * @return CalendarDate
359 366
 	 */
360
-	public function maximumDate() {
367
+	public function maximumDate()
368
+	{
361 369
 		if (is_null($this->date2)) {
362 370
 			return $this->date1;
363 371
 		} else {
@@ -370,7 +378,8 @@  discard block
 block discarded – undo
370 378
 	 *
371 379
 	 * @return int
372 380
 	 */
373
-	public function minimumJulianDay() {
381
+	public function minimumJulianDay()
382
+	{
374 383
 		return $this->minimumDate()->minJD;
375 384
 	}
376 385
 
@@ -379,7 +388,8 @@  discard block
 block discarded – undo
379 388
 	 *
380 389
 	 * @return int
381 390
 	 */
382
-	public function maximumJulianDay() {
391
+	public function maximumJulianDay()
392
+	{
383 393
 		return $this->maximumDate()->maxJD;
384 394
 	}
385 395
 
@@ -391,7 +401,8 @@  discard block
 block discarded – undo
391 401
 	 *
392 402
 	 * @return int
393 403
 	 */
394
-	public function julianDay() {
404
+	public function julianDay()
405
+	{
395 406
 		return (int) (($this->minimumJulianDay() + $this->maximumJulianDay()) / 2);
396 407
 	}
397 408
 
@@ -406,7 +417,8 @@  discard block
 block discarded – undo
406 417
 	 *
407 418
 	 * @return Date
408 419
 	 */
409
-	public function addYears($years, $qualifier = '') {
420
+	public function addYears($years, $qualifier = '')
421
+	{
410 422
 		$tmp = clone $this;
411 423
 		$tmp->date1->y += $years;
412 424
 		$tmp->date1->m = 0;
@@ -430,7 +442,8 @@  discard block
 block discarded – undo
430 442
 	 *
431 443
 	 * @return int|string
432 444
 	 */
433
-	public static function getAge(Date $d1, Date $d2 = null, $format = 0) {
445
+	public static function getAge(Date $d1, Date $d2 = null, $format = 0)
446
+	{
434 447
 		if ($d2) {
435 448
 			if ($d2->maximumJulianDay() >= $d1->minimumJulianDay() && $d2->minimumJulianDay() <= $d1->minimumJulianDay()) {
436 449
 				// Overlapping dates
@@ -484,7 +497,8 @@  discard block
 block discarded – undo
484 497
 	 *
485 498
 	 * @return string
486 499
 	 */
487
-	public static function getAgeGedcom(Date $d1, Date $d2 = null) {
500
+	public static function getAgeGedcom(Date $d1, Date $d2 = null)
501
+	{
488 502
 		if (is_null($d2)) {
489 503
 			return $d1->date1->getAge(true, WT_CLIENT_JD, true);
490 504
 		} else {
@@ -512,7 +526,8 @@  discard block
 block discarded – undo
512 526
 	 *
513 527
 	 * @return int
514 528
 	 */
515
-	public static function compare(Date $a, Date $b) {
529
+	public static function compare(Date $a, Date $b)
530
+	{
516 531
 		// Get min/max JD for each date.
517 532
 		switch ($a->qual1) {
518 533
 		case 'BEF':
@@ -563,7 +578,8 @@  discard block
 block discarded – undo
563 578
 	 *
564 579
 	 * @return bool
565 580
 	 */
566
-	public function isOK() {
581
+	public function isOK()
582
+	{
567 583
 		return $this->minimumJulianDay() && $this->maximumJulianDay();
568 584
 	}
569 585
 
@@ -575,7 +591,8 @@  discard block
 block discarded – undo
575 591
 	 *
576 592
 	 * @return int
577 593
 	 */
578
-	public function gregorianYear() {
594
+	public function gregorianYear()
595
+	{
579 596
 		if ($this->isOK()) {
580 597
 			$gregorian_calendar = new GregorianCalendar;
581 598
 			list($year)         = $gregorian_calendar->jdToYmd($this->julianDay());
Please login to merge, or discard this patch.
app/Functions/Functions.php 3 patches
Indentation   +2132 added lines, -2132 removed lines patch added patch discarded remove patch
@@ -27,2193 +27,2193 @@
 block discarded – undo
27 27
  * Class Functions - common functions
28 28
  */
29 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) {
46
-				Site::setPreference('LATEST_WT_VERSION', $latest_version_txt);
47
-				Site::setPreference('LATEST_WT_VERSION_TIMESTAMP', WT_TIMESTAMP);
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) {
46
+                Site::setPreference('LATEST_WT_VERSION', $latest_version_txt);
47
+                Site::setPreference('LATEST_WT_VERSION_TIMESTAMP', WT_TIMESTAMP);
48 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
-	}
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 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
-	}
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 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);
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);
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);
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 143
 
144
-		return ltrim($subrec);
145
-	}
144
+        return ltrim($subrec);
145
+    }
146 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 = '';
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 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
-		}
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 170
 
171
-		return $text;
172
-	}
171
+        return $text;
172
+    }
173 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
-		}
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 197
 
198
-		//-- sort each type of array
199
-		usort($dated, '\Fisharebest\Webtrees\Fact::compareDate');
200
-		usort($nondated, '\Fisharebest\Webtrees\Fact::compareType');
198
+        //-- sort each type of array
199
+        usort($dated, '\Fisharebest\Webtrees\Fact::compareDate');
200
+        usort($nondated, '\Fisharebest\Webtrees\Fact::compareType');
201 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
-		}
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 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
-		}
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 227
 
228
-	}
228
+    }
229 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
238
-	 */
239
-	public static function getCloseRelationshipName(Individual $individual1, Individual $individual2) {
240
-		if ($individual1 === $individual2) {
241
-			$label = '<i class="icon-selected"></i> ' . self::reflexivePronoun($individual1);
242
-		} else {
243
-			$label = self::getRelationshipName(self::getRelationship($individual1, $individual2));
244
-		}
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
238
+     */
239
+    public static function getCloseRelationshipName(Individual $individual1, Individual $individual2) {
240
+        if ($individual1 === $individual2) {
241
+            $label = '<i class="icon-selected"></i> ' . self::reflexivePronoun($individual1);
242
+        } else {
243
+            $label = self::getRelationshipName(self::getRelationship($individual1, $individual2));
244
+        }
245 245
 
246
-		return $label;
247
-	}
246
+        return $label;
247
+    }
248 248
 
249
-	/**
250
-	 * For facts on the individual/family pages.
251
-	 *
252
-	 * @param Individual $individual1
253
-	 * @param Individual $individual2
254
-	 *
255
-	 * @return string
256
-	 */
257
-	public static function getAssociateRelationshipName(Individual $individual1, Individual $individual2) {
258
-		if ($individual1 === $individual2) {
259
-			$label = self::reflexivePronoun($individual1);
260
-		} else {
261
-			$label = self::getRelationshipName(self::getRelationship($individual1, $individual2));
262
-		}
249
+    /**
250
+     * For facts on the individual/family pages.
251
+     *
252
+     * @param Individual $individual1
253
+     * @param Individual $individual2
254
+     *
255
+     * @return string
256
+     */
257
+    public static function getAssociateRelationshipName(Individual $individual1, Individual $individual2) {
258
+        if ($individual1 === $individual2) {
259
+            $label = self::reflexivePronoun($individual1);
260
+        } else {
261
+            $label = self::getRelationshipName(self::getRelationship($individual1, $individual2));
262
+        }
263 263
 
264
-		return $label;
265
-	}
264
+        return $label;
265
+    }
266 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
-	}
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 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
293
-	 */
294
-	public static function getRelationship(Individual $person1, Individual $person2, $maxlength = 4) {
295
-		if ($person1 === $person2) {
296
-			return false;
297
-		}
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
293
+     */
294
+    public static function getRelationship(Individual $person1, Individual $person2, $maxlength = 4) {
295
+        if ($person1 === $person2) {
296
+            return false;
297
+        }
298 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');
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 303
 
304
-		//-- current path nodes
305
-		$p1nodes = array();
306
-		//-- ids visited
307
-		$visited = array();
304
+        //-- current path nodes
305
+        $p1nodes = array();
306
+        //-- ids visited
307
+        $visited = array();
308 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;
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 317
 
318
-		$visited[$person1->getXref()] = true;
318
+        $visited[$person1->getXref()] = true;
319 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
-				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
-				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
-		}
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
+                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
+                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 415
 
416
-		return $resnode;
417
-	}
416
+        return $resnode;
417
+    }
418 418
 
419
-	/**
420
-	 * Convert the result of get_relationship() into a relationship name.
421
-	 *
422
-	 * @param mixed[][] $nodes
423
-	 *
424
-	 * @return string
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.
419
+    /**
420
+     * Convert the result of get_relationship() into a relationship name.
421
+     *
422
+     * @param mixed[][] $nodes
423
+     *
424
+     * @return string
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 448
 
449
-		return self::getRelationshipNameFromPath(
450
-			implode('', $path),
451
-			$person1,
452
-			$person2
453
-		);
454
-	}
449
+        return self::getRelationshipNameFromPath(
450
+            implode('', $path),
451
+            $person1,
452
+            $person2
453
+        );
454
+    }
455 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
-		case 'M':
467
-			switch ($n) {
468
-			case  1:
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:
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:
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:
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:
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:
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:
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:
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:
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
-		case 'F':
518
-			switch ($n) {
519
-			case  1:
520
-			return I18N::translateContext('FEMALE', 'first cousin');
521
-			case  2:
522
-			return I18N::translateContext('FEMALE', 'second cousin');
523
-			case  3:
524
-			return I18N::translateContext('FEMALE', 'third cousin');
525
-			case  4:
526
-			return I18N::translateContext('FEMALE', 'fourth cousin');
527
-			case  5:
528
-			return I18N::translateContext('FEMALE', 'fifth cousin');
529
-			case  6:
530
-			return I18N::translateContext('FEMALE', 'sixth cousin');
531
-			case  7:
532
-			return I18N::translateContext('FEMALE', 'seventh cousin');
533
-			case  8:
534
-			return I18N::translateContext('FEMALE', 'eighth cousin');
535
-			case  9:
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:
555
-			return I18N::translate('first cousin');
556
-			case  2:
557
-			return I18N::translate('second cousin');
558
-			case  3:
559
-			return I18N::translate('third cousin');
560
-			case  4:
561
-			return I18N::translate('fourth cousin');
562
-			case  5:
563
-			return I18N::translate('fifth cousin');
564
-			case  6:
565
-			return I18N::translate('sixth cousin');
566
-			case  7:
567
-			return I18N::translate('seventh cousin');
568
-			case  8:
569
-			return I18N::translate('eighth cousin');
570
-			case  9:
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
-	}
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
+        case 'M':
467
+            switch ($n) {
468
+            case  1:
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:
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:
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:
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:
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:
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:
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:
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:
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
+        case 'F':
518
+            switch ($n) {
519
+            case  1:
520
+            return I18N::translateContext('FEMALE', 'first cousin');
521
+            case  2:
522
+            return I18N::translateContext('FEMALE', 'second cousin');
523
+            case  3:
524
+            return I18N::translateContext('FEMALE', 'third cousin');
525
+            case  4:
526
+            return I18N::translateContext('FEMALE', 'fourth cousin');
527
+            case  5:
528
+            return I18N::translateContext('FEMALE', 'fifth cousin');
529
+            case  6:
530
+            return I18N::translateContext('FEMALE', 'sixth cousin');
531
+            case  7:
532
+            return I18N::translateContext('FEMALE', 'seventh cousin');
533
+            case  8:
534
+            return I18N::translateContext('FEMALE', 'eighth cousin');
535
+            case  9:
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:
555
+            return I18N::translate('first cousin');
556
+            case  2:
557
+            return I18N::translate('second cousin');
558
+            case  3:
559
+            return I18N::translate('third cousin');
560
+            case  4:
561
+            return I18N::translate('fourth cousin');
562
+            case  5:
563
+            return I18N::translate('fifth cousin');
564
+            case  6:
565
+            return I18N::translate('sixth cousin');
566
+            case  7:
567
+            return I18N::translate('seventh cousin');
568
+            case  8:
569
+            return I18N::translate('eighth cousin');
570
+            case  9:
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 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
-		case 'M':
603
-			switch ($n) {
604
-			case  1:
605
-				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('MALE', 'first %s', $relation);
606
-			case  2:
607
-				return I18N::translateContext('MALE', 'second %s', $relation);
608
-			case  3:
609
-				return I18N::translateContext('MALE', 'third %s', $relation);
610
-			case  4:
611
-				return I18N::translateContext('MALE', 'fourth %s', $relation);
612
-			case  5:
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
-		case 'F':
618
-			switch ($n) {
619
-			case  1:
620
-				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('FEMALE', 'first %s', $relation);
621
-			case  2:
622
-				return I18N::translateContext('FEMALE', 'second %s', $relation);
623
-			case  3:
624
-				return I18N::translateContext('FEMALE', 'third %s', $relation);
625
-			case  4:
626
-				return I18N::translateContext('FEMALE', 'fourth %s', $relation);
627
-			case  5:
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:
635
-				return /* I18N: A Spanish relationship name, such as first great-nephew */ I18N::translate('first %s', $relation);
636
-			case  2:
637
-				return /* I18N: A Spanish relationship name, such as second great-nephew */ I18N::translate('second %s', $relation);
638
-			case  3:
639
-				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translate('third %s', $relation);
640
-			case  4:
641
-				return /* I18N: A Spanish relationship name, such as fourth great-nephew */ I18N::translate('fourth %s', $relation);
642
-			case  5:
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
-	}
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
+        case 'M':
603
+            switch ($n) {
604
+            case  1:
605
+                return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('MALE', 'first %s', $relation);
606
+            case  2:
607
+                return I18N::translateContext('MALE', 'second %s', $relation);
608
+            case  3:
609
+                return I18N::translateContext('MALE', 'third %s', $relation);
610
+            case  4:
611
+                return I18N::translateContext('MALE', 'fourth %s', $relation);
612
+            case  5:
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
+        case 'F':
618
+            switch ($n) {
619
+            case  1:
620
+                return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('FEMALE', 'first %s', $relation);
621
+            case  2:
622
+                return I18N::translateContext('FEMALE', 'second %s', $relation);
623
+            case  3:
624
+                return I18N::translateContext('FEMALE', 'third %s', $relation);
625
+            case  4:
626
+                return I18N::translateContext('FEMALE', 'fourth %s', $relation);
627
+            case  5:
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:
635
+                return /* I18N: A Spanish relationship name, such as first great-nephew */ I18N::translate('first %s', $relation);
636
+            case  2:
637
+                return /* I18N: A Spanish relationship name, such as second great-nephew */ I18N::translate('second %s', $relation);
638
+            case  3:
639
+                return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translate('third %s', $relation);
640
+            case  4:
641
+                return /* I18N: A Spanish relationship name, such as fourth great-nephew */ I18N::translate('fourth %s', $relation);
642
+            case  5:
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 649
 
650
-	/** @var string[] Cache for generic relationships (key stores the path, and value represents the relationship name) */
651
-	protected static $relationshipsCache = array();
650
+    /** @var string[] Cache for generic relationships (key stores the path, and value represents the relationship name) */
651
+    protected static $relationshipsCache = array();
652 652
 
653
-	/**
654
-	 * Convert a relationship path into a relationship name.
655
-	 *
656
-	 * @param string $path
657
-	 * @param Individual $person1
658
-	 * @param Individual $person2
659
-	 *
660
-	 * @return string
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
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';
653
+    /**
654
+     * Convert a relationship path into a relationship name.
655
+     *
656
+     * @param string $path
657
+     * @param Individual $person1
658
+     * @param Individual $person2
659
+     *
660
+     * @return string
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
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 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
-		}
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 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
-		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
-			}
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
+        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 708
 
709
-			return I18N::translate('husband');
710
-		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
-			}
709
+            return I18N::translate('husband');
710
+        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 726
 
727
-			return I18N::translate('wife');
728
-		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
-			}
727
+            return I18N::translate('wife');
728
+        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 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
-		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
-			}
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
+        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 767
 
768
-			return I18N::translate('brother');
769
-		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
-			}
768
+            return I18N::translate('brother');
769
+        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 784
 
785
-			return I18N::translate('sister');
786
-		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
-			}
785
+            return I18N::translate('sister');
786
+        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 801
 
802
-			return I18N::translate('sibling');
802
+            return I18N::translate('sibling');
803 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');
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 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':
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
-		case 'brochidau':
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
-		case 'brochison':
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':
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
-		case 'brodaudau':
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
-		case 'brodauson':
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':
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
-		case 'brosondau':
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
-		case 'brosonson':
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':
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
-		case 'sischidau':
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
-		case 'sischison':
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':
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
-		case 'sisdaudau':
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
-		case 'sisdauson':
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':
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
-		case 'sissondau':
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
-		case 'sissonson':
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');
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':
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
+        case 'brochidau':
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
+        case 'brochison':
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':
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
+        case 'brodaudau':
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
+        case 'brodauson':
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':
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
+        case 'brosondau':
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
+        case 'brosonson':
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':
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
+        case 'sischidau':
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
+        case 'sischison':
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':
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
+        case 'sisdaudau':
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
+        case 'sisdauson':
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':
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
+        case 'sissondau':
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
+        case 'sissonson':
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 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
-		}
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 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
-		}
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 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
-			case 3:
1539
-				switch ($sex2) {
1540
-				case 'M':
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
-			case 4:
1554
-				switch ($sex2) {
1555
-				case 'M':
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
-			case 5:
1569
-				switch ($sex2) {
1570
-				case 'M':
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
-			case 6:
1584
-				switch ($sex2) {
1585
-				case 'M':
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
-			case 7:
1599
-				switch ($sex2) {
1600
-				case 'M':
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
-			case 8:
1614
-				switch ($sex2) {
1615
-				case 'M':
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
-				case 'da':
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':
1644
-					switch ($sex2) {
1645
-					case 'M':
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
-				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
-			case 4:
1680
-				switch ($sex2) {
1681
-				case 'M':
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':
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
-			case 5:
1707
-				switch ($sex2) {
1708
-				case 'M':
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':
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
-			case 6:
1734
-				switch ($sex2) {
1735
-				case 'M':
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':
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
-			case 7:
1761
-				switch ($sex2) {
1762
-				case 'M':
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':
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
1794
-				switch ($sex2) {
1795
-				case 'M':
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
-				case 'F':
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
-				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
-				case 'he': // Source: Meliza Amity
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
-				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:
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:
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
-			case 6:
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
-			case 7:
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
-			case 8:
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
-			case 9:
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
-				case 'da': // Source: Patrick Sorensen
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
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
-				case 'fr_CA':
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
-				case 'nb':
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
-				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:
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
-				}
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
+            case 3:
1539
+                switch ($sex2) {
1540
+                case 'M':
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
+            case 4:
1554
+                switch ($sex2) {
1555
+                case 'M':
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
+            case 5:
1569
+                switch ($sex2) {
1570
+                case 'M':
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
+            case 6:
1584
+                switch ($sex2) {
1585
+                case 'M':
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
+            case 7:
1599
+                switch ($sex2) {
1600
+                case 'M':
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
+            case 8:
1614
+                switch ($sex2) {
1615
+                case 'M':
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
+                case 'da':
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':
1644
+                    switch ($sex2) {
1645
+                    case 'M':
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
+                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
+            case 4:
1680
+                switch ($sex2) {
1681
+                case 'M':
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':
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
+            case 5:
1707
+                switch ($sex2) {
1708
+                case 'M':
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':
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
+            case 6:
1734
+                switch ($sex2) {
1735
+                case 'M':
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':
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
+            case 7:
1761
+                switch ($sex2) {
1762
+                case 'M':
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':
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
1794
+                switch ($sex2) {
1795
+                case 'M':
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
+                case 'F':
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
+                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
+                case 'he': // Source: Meliza Amity
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
+                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:
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:
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
+            case 6:
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
+            case 7:
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
+            case 8:
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
+            case 9:
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
+                case 'da': // Source: Patrick Sorensen
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
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
+                case 'fr_CA':
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
+                case 'nb':
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
+                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:
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 1976
 
1977
-			case 5:
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
-				}
1977
+            case 5:
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 1986
 
1987
-			case 6:
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
-				}
1987
+            case 6:
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 1996
 
1997
-			case 7:
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
-				}
1997
+            case 7:
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 2006
 
2007
-			case 8:
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
-				}
2007
+            case 8:
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 2016
 
2017
-			case 9:
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
-				}
2017
+            case 9:
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 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
-				case 'da': // Source: Patrick Sorensen
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
-				default:
2050
-					switch ($sex2) {
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
+                case 'da': // Source: Patrick Sorensen
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
+                default:
2050
+                    switch ($sex2) {
2051 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.
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 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':
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
-					case 'M':
2091
-					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('bro' . $descent, null, null));
2092
-					case 'F':
2093
-					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sis' . $descent, null, null));
2094
-					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
-				case 1:
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
-				case 2:
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
-				case 3:
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
-		}
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':
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
+                    case 'M':
2091
+                    return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('bro' . $descent, null, null));
2092
+                    case 'F':
2093
+                    return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sis' . $descent, null, null));
2094
+                    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
+                case 1:
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
+                case 2:
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
+                case 3:
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 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
-		}
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 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
2156
-				self::getRelationshipNameFromPath($path2, null, null)
2157
-			);
2158
-			if (!$relationship || strlen($tmp) < strlen($relationship)) {
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;
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
2156
+                self::getRelationshipNameFromPath($path2, null, null)
2157
+            );
2158
+            if (!$relationship || strlen($tmp) < strlen($relationship)) {
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 2166
 
2167
-		return $relationship;
2168
-	}
2167
+        return $relationship;
2168
+    }
2169 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 = '&') {
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
-		}
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 = '&') {
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 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
-	}
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 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
-	}
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 2219
 }
Please login to merge, or discard this patch.
Switch Indentation   +1483 added lines, -1483 removed lines patch added patch discarded remove patch
@@ -65,29 +65,29 @@  discard block
 block discarded – undo
65 65
 	 */
66 66
 	public static function fileUploadErrorText($error_code) {
67 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;
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 91
 		}
92 92
 	}
93 93
 
@@ -273,12 +273,12 @@  discard block
 block discarded – undo
273 273
 	 */
274 274
 	private static function reflexivePronoun(Individual $individual) {
275 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');
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 282
 		}
283 283
 	}
284 284
 
@@ -463,127 +463,127 @@  discard block
 block discarded – undo
463 463
 	 */
464 464
 	public static function cousinName($n, $sex) {
465 465
 		switch ($sex) {
466
-		case 'M':
467
-			switch ($n) {
468
-			case  1:
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:
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:
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:
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:
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:
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:
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:
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:
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
-		case 'F':
518
-			switch ($n) {
519
-			case  1:
520
-			return I18N::translateContext('FEMALE', 'first cousin');
521
-			case  2:
522
-			return I18N::translateContext('FEMALE', 'second cousin');
523
-			case  3:
524
-			return I18N::translateContext('FEMALE', 'third cousin');
525
-			case  4:
526
-			return I18N::translateContext('FEMALE', 'fourth cousin');
527
-			case  5:
528
-			return I18N::translateContext('FEMALE', 'fifth cousin');
529
-			case  6:
530
-			return I18N::translateContext('FEMALE', 'sixth cousin');
531
-			case  7:
532
-			return I18N::translateContext('FEMALE', 'seventh cousin');
533
-			case  8:
534
-			return I18N::translateContext('FEMALE', 'eighth cousin');
535
-			case  9:
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:
555
-			return I18N::translate('first cousin');
556
-			case  2:
557
-			return I18N::translate('second cousin');
558
-			case  3:
559
-			return I18N::translate('third cousin');
560
-			case  4:
561
-			return I18N::translate('fourth cousin');
562
-			case  5:
563
-			return I18N::translate('fifth cousin');
564
-			case  6:
565
-			return I18N::translate('sixth cousin');
566
-			case  7:
567
-			return I18N::translate('seventh cousin');
568
-			case  8:
569
-			return I18N::translate('eighth cousin');
570
-			case  9:
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
-			}
466
+		    case 'M':
467
+			    switch ($n) {
468
+			        case  1:
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:
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:
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:
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:
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:
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:
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:
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:
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
+		    case 'F':
518
+			    switch ($n) {
519
+			        case  1:
520
+			        return I18N::translateContext('FEMALE', 'first cousin');
521
+			        case  2:
522
+			        return I18N::translateContext('FEMALE', 'second cousin');
523
+			        case  3:
524
+			        return I18N::translateContext('FEMALE', 'third cousin');
525
+			        case  4:
526
+			        return I18N::translateContext('FEMALE', 'fourth cousin');
527
+			        case  5:
528
+			        return I18N::translateContext('FEMALE', 'fifth cousin');
529
+			        case  6:
530
+			        return I18N::translateContext('FEMALE', 'sixth cousin');
531
+			        case  7:
532
+			        return I18N::translateContext('FEMALE', 'seventh cousin');
533
+			        case  8:
534
+			        return I18N::translateContext('FEMALE', 'eighth cousin');
535
+			        case  9:
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:
555
+			        return I18N::translate('first cousin');
556
+			        case  2:
557
+			        return I18N::translate('second cousin');
558
+			        case  3:
559
+			        return I18N::translate('third cousin');
560
+			        case  4:
561
+			        return I18N::translate('fourth cousin');
562
+			        case  5:
563
+			        return I18N::translate('fifth cousin');
564
+			        case  6:
565
+			        return I18N::translate('sixth cousin');
566
+			        case  7:
567
+			        return I18N::translate('seventh cousin');
568
+			        case  8:
569
+			        return I18N::translate('eighth cousin');
570
+			        case  9:
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 587
 		}
588 588
 	}
589 589
 
@@ -599,51 +599,51 @@  discard block
 block discarded – undo
599 599
 	 */
600 600
 	public static function cousinName2($n, $sex, $relation) {
601 601
 		switch ($sex) {
602
-		case 'M':
603
-			switch ($n) {
604
-			case  1:
605
-				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('MALE', 'first %s', $relation);
606
-			case  2:
607
-				return I18N::translateContext('MALE', 'second %s', $relation);
608
-			case  3:
609
-				return I18N::translateContext('MALE', 'third %s', $relation);
610
-			case  4:
611
-				return I18N::translateContext('MALE', 'fourth %s', $relation);
612
-			case  5:
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
-		case 'F':
618
-			switch ($n) {
619
-			case  1:
620
-				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('FEMALE', 'first %s', $relation);
621
-			case  2:
622
-				return I18N::translateContext('FEMALE', 'second %s', $relation);
623
-			case  3:
624
-				return I18N::translateContext('FEMALE', 'third %s', $relation);
625
-			case  4:
626
-				return I18N::translateContext('FEMALE', 'fourth %s', $relation);
627
-			case  5:
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:
635
-				return /* I18N: A Spanish relationship name, such as first great-nephew */ I18N::translate('first %s', $relation);
636
-			case  2:
637
-				return /* I18N: A Spanish relationship name, such as second great-nephew */ I18N::translate('second %s', $relation);
638
-			case  3:
639
-				return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translate('third %s', $relation);
640
-			case  4:
641
-				return /* I18N: A Spanish relationship name, such as fourth great-nephew */ I18N::translate('fourth %s', $relation);
642
-			case  5:
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
-			}
602
+		    case 'M':
603
+			    switch ($n) {
604
+			        case  1:
605
+				        return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('MALE', 'first %s', $relation);
606
+			        case  2:
607
+				        return I18N::translateContext('MALE', 'second %s', $relation);
608
+			        case  3:
609
+				        return I18N::translateContext('MALE', 'third %s', $relation);
610
+			        case  4:
611
+				        return I18N::translateContext('MALE', 'fourth %s', $relation);
612
+			        case  5:
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
+		    case 'F':
618
+			    switch ($n) {
619
+			        case  1:
620
+				        return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translateContext('FEMALE', 'first %s', $relation);
621
+			        case  2:
622
+				        return I18N::translateContext('FEMALE', 'second %s', $relation);
623
+			        case  3:
624
+				        return I18N::translateContext('FEMALE', 'third %s', $relation);
625
+			        case  4:
626
+				        return I18N::translateContext('FEMALE', 'fourth %s', $relation);
627
+			        case  5:
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:
635
+				        return /* I18N: A Spanish relationship name, such as first great-nephew */ I18N::translate('first %s', $relation);
636
+			        case  2:
637
+				        return /* I18N: A Spanish relationship name, such as second great-nephew */ I18N::translate('second %s', $relation);
638
+			        case  3:
639
+				        return /* I18N: A Spanish relationship name, such as third great-nephew */ I18N::translate('third %s', $relation);
640
+			        case  4:
641
+				        return /* I18N: A Spanish relationship name, such as fourth great-nephew */ I18N::translate('fourth %s', $relation);
642
+			        case  5:
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 647
 		}
648 648
 	}
649 649
 
@@ -680,796 +680,796 @@  discard block
 block discarded – undo
680 680
 		}
681 681
 
682 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
-		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
-			}
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
+		    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 708
 
709
-			return I18N::translate('husband');
710
-		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
-			}
709
+			    return I18N::translate('husband');
710
+		    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 726
 
727
-			return I18N::translate('wife');
728
-		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
-			}
727
+			    return I18N::translate('wife');
728
+		    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 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
-		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
-			}
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
+		    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 767
 
768
-			return I18N::translate('brother');
769
-		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
-			}
768
+			    return I18N::translate('brother');
769
+		    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 784
 
785
-			return I18N::translate('sister');
786
-		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
-			}
785
+			    return I18N::translate('sister');
786
+		    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 801
 
802
-			return I18N::translate('sibling');
802
+			    return I18N::translate('sibling');
803 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');
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 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':
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
-		case 'brochidau':
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
-		case 'brochison':
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':
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
-		case 'brodaudau':
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
-		case 'brodauson':
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':
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
-		case 'brosondau':
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
-		case 'brosonson':
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':
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
-		case 'sischidau':
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
-		case 'sischison':
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':
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
-		case 'sisdaudau':
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
-		case 'sisdauson':
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':
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
-		case 'sissondau':
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
-		case 'sissonson':
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');
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':
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
+		    case 'brochidau':
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
+		    case 'brochison':
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':
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
+		    case 'brodaudau':
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
+		    case 'brodauson':
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':
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
+		    case 'brosondau':
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
+		    case 'brosonson':
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':
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
+		    case 'sischidau':
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
+		    case 'sischison':
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':
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
+		    case 'sisdaudau':
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
+		    case 'sisdauson':
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':
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
+		    case 'sissondau':
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
+		    case 'sissonson':
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 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');
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 1473
 		}
1474 1474
 
1475 1475
 		// Some “special case” level five relationships that have specific names in certain languages
@@ -1535,125 +1535,125 @@  discard block
 block discarded – undo
1535 1535
 			$up       = strlen($match[1]) / 3;
1536 1536
 			$bef_last = substr($path, -6, 3);
1537 1537
 			switch ($up) {
1538
-			case 3:
1539
-				switch ($sex2) {
1540
-				case 'M':
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
-			case 4:
1554
-				switch ($sex2) {
1555
-				case 'M':
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
-			case 5:
1569
-				switch ($sex2) {
1570
-				case 'M':
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
-			case 6:
1584
-				switch ($sex2) {
1585
-				case 'M':
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
-			case 7:
1599
-				switch ($sex2) {
1600
-				case 'M':
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
-			case 8:
1614
-				switch ($sex2) {
1615
-				case 'M':
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
-				case 'da':
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
-				}
1538
+			    case 3:
1539
+				    switch ($sex2) {
1540
+				        case 'M':
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
+			    case 4:
1554
+				    switch ($sex2) {
1555
+				        case 'M':
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
+			    case 5:
1569
+				    switch ($sex2) {
1570
+				        case 'M':
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
+			    case 6:
1584
+				    switch ($sex2) {
1585
+				        case 'M':
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
+			    case 7:
1599
+				    switch ($sex2) {
1600
+				        case 'M':
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
+			    case 8:
1614
+				    switch ($sex2) {
1615
+				        case 'M':
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
+				        case 'da':
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 1643
 				case 'pl':
1644 1644
 					switch ($sex2) {
1645
-					case 'M':
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));
1645
+					    case 'M':
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 1657
 					}
1658 1658
 				case 'it': // Source: Michele Locati
1659 1659
 				case 'en_AU':
@@ -1661,12 +1661,12 @@  discard block
 block discarded – undo
1661 1661
 				case 'en_US':
1662 1662
 				default:
1663 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));
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 1670
 					}
1671 1671
 					}
1672 1672
 			}
@@ -1676,155 +1676,155 @@  discard block
 block discarded – undo
1676 1676
 			$down  = strlen($match[1]) / 3 + 1; // Add one, as we count generations from the common ancestor
1677 1677
 			$first = substr($path, 0, 3);
1678 1678
 			switch ($down) {
1679
-			case 4:
1680
-				switch ($sex2) {
1681
-				case 'M':
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':
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
-			case 5:
1707
-				switch ($sex2) {
1708
-				case 'M':
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':
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
-			case 6:
1734
-				switch ($sex2) {
1735
-				case 'M':
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':
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
-			case 7:
1761
-				switch ($sex2) {
1762
-				case 'M':
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':
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
1794
-				switch ($sex2) {
1795
-				case 'M':
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
-				case 'F':
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
-				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
-				}
1679
+			    case 4:
1680
+				    switch ($sex2) {
1681
+				        case 'M':
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':
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
+			    case 5:
1707
+				    switch ($sex2) {
1708
+				        case 'M':
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':
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
+			    case 6:
1734
+				    switch ($sex2) {
1735
+				        case 'M':
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':
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
+			    case 7:
1761
+				    switch ($sex2) {
1762
+				        case 'M':
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':
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
1794
+				        switch ($sex2) {
1795
+				            case 'M':
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
+				            case 'F':
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
+				            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 1820
 				case 'he': // Source: Meliza Amity
1821 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));
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 1828
 					}
1829 1829
 				case 'it': // Source: Michele Locati.
1830 1830
 				case 'en_AU':
@@ -1832,12 +1832,12 @@  discard block
 block discarded – undo
1832 1832
 				case 'en_US':
1833 1833
 				default:
1834 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));
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 1841
 					}
1842 1842
 					}
1843 1843
 			}
@@ -1846,116 +1846,116 @@  discard block
 block discarded – undo
1846 1846
 			// direct ancestors
1847 1847
 			$up = strlen($match[1]) / 3;
1848 1848
 			switch ($up) {
1849
-			case 4:
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:
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
-			case 6:
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
-			case 7:
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
-			case 8:
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
-			case 9:
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
-				case 'da': // Source: Patrick Sorensen
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
-				}
1849
+			    case 4:
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:
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
+			    case 6:
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
+			    case 7:
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
+			    case 8:
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
+			    case 9:
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
+				        case 'da': // Source: Patrick Sorensen
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 1918
 				case 'it': // Source: Michele Locati
1919 1919
 				case 'es': // Source: Wes Groleau
1920 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));
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 1927
 					}
1928 1928
 				case 'fr': // Source: Jacqueline Tetreault
1929 1929
 				case 'fr_CA':
1930 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));
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 1937
 					}
1938 1938
 				case 'nn': // Source: Hogne Røed Nilsen (https://bugs.launchpad.net/webtrees/+bug/1168553)
1939 1939
 				case 'nb':
1940 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));
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 1947
 					}
1948 1948
 				case 'en_AU':
1949 1949
 				case 'en_GB':
1950 1950
 				case 'en_US':
1951 1951
 				default:
1952 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));
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 1959
 					}
1960 1960
 					}
1961 1961
 			}
@@ -1964,83 +1964,83 @@  discard block
 block discarded – undo
1964 1964
 			// direct descendants
1965 1965
 			$up = strlen($match[1]) / 3;
1966 1966
 			switch ($up) {
1967
-			case 4:
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
-				}
1967
+			    case 4:
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 1976
 
1977
-			case 5:
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
-				}
1977
+			    case 5:
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 1986
 
1987
-			case 6:
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
-				}
1987
+			    case 6:
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 1996
 
1997
-			case 7:
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
-				}
1997
+			    case 7:
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 2006
 
2007
-			case 8:
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
-				}
2007
+			    case 8:
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 2016
 
2017
-			case 9:
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
-				}
2017
+			    case 9:
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 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
-				case 'da': // Source: Patrick Sorensen
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
-				}
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
+				        case 'da': // Source: Patrick Sorensen
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 2044
 				case 'it': // Source: Michele Locati
2045 2045
 				case 'es': // Source: Wes Groleau (adding doesn’t change behavior, but needs to be better researched)
2046 2046
 				case 'en_AU':
@@ -2049,12 +2049,12 @@  discard block
 block discarded – undo
2049 2049
 				default:
2050 2050
 					switch ($sex2) {
2051 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));
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 2058
 					}
2059 2059
 					}
2060 2060
 			}
@@ -2073,68 +2073,68 @@  discard block
 block discarded – undo
2073 2073
 			//
2074 2074
 			// Need to find out which languages use which rules.
2075 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':
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
-					case 'M':
2091
-					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('bro' . $descent, null, null));
2092
-					case 'F':
2093
-					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sis' . $descent, null, null));
2094
-					default:
2095
-					return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sib' . $descent, null, null));
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':
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
+					        case 'M':
2091
+					        return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('bro' . $descent, null, null));
2092
+					        case 'F':
2093
+					        return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sis' . $descent, null, null));
2094
+					        default:
2095
+					        return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sib' . $descent, null, null));
2096
+					    }
2096 2097
 					}
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
-				case 1:
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
-				case 2:
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
-				case 3:
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
-				}
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
+				        case 1:
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
+				        case 2:
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
+				        case 3:
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 2138
 			}
2139 2139
 		}
2140 2140
 
Please login to merge, or discard this patch.
Braces   +32 added lines, -16 removed lines patch added patch discarded remove patch
@@ -26,7 +26,8 @@  discard block
 block discarded – undo
26 26
 /**
27 27
  * Class Functions - common functions
28 28
  */
29
-class Functions {
29
+class Functions
30
+{
30 31
 	/**
31 32
 	 * Check with the webtrees.net server for the latest version of webtrees.
32 33
 	 * Fetching the remote file can be slow, so check infrequently, and cache the result.
@@ -36,7 +37,8 @@  discard block
 block discarded – undo
36 37
 	 *
37 38
 	 * @return null|string
38 39
 	 */
39
-	public static function fetchLatestVersion() {
40
+	public static function fetchLatestVersion()
41
+	{
40 42
 		$last_update_timestamp = Site::getPreference('LATEST_WT_VERSION_TIMESTAMP');
41 43
 		if ($last_update_timestamp < WT_TIMESTAMP - 24 * 60 * 60) {
42 44
 			$row                = Database::prepare("SHOW VARIABLES LIKE 'version'")->fetchOneRow();
@@ -63,7 +65,8 @@  discard block
 block discarded – undo
63 65
 	 *
64 66
 	 * @return string
65 67
 	 */
66
-	public static function fileUploadErrorText($error_code) {
68
+	public static function fileUploadErrorText($error_code)
69
+	{
67 70
 		switch ($error_code) {
68 71
 		case UPLOAD_ERR_OK:
69 72
 			return I18N::translate('File successfully uploaded');
@@ -113,7 +116,8 @@  discard block
 block discarded – undo
113 116
 	 *
114 117
 	 * @return string the subrecord that was found or an empty string "" if not found.
115 118
 	 */
116
-	public static function getSubRecord($level, $tag, $gedrec, $num = 1) {
119
+	public static function getSubRecord($level, $tag, $gedrec, $num = 1)
120
+	{
117 121
 		if (empty($gedrec)) {
118 122
 			return '';
119 123
 		}
@@ -154,7 +158,8 @@  discard block
 block discarded – undo
154 158
 	 *
155 159
 	 * @return string a string with all CONT lines merged
156 160
 	 */
157
-	public static function getCont($nlevel, $nrec) {
161
+	public static function getCont($nlevel, $nrec)
162
+	{
158 163
 		$text = '';
159 164
 
160 165
 		$subrecords = explode("\n", $nrec);
@@ -180,7 +185,8 @@  discard block
 block discarded – undo
180 185
 	 *
181 186
 	 * @param Fact[] $arr
182 187
 	 */
183
-	public static function sortFacts(&$arr) {
188
+	public static function sortFacts(&$arr)
189
+	{
184 190
 		$dated    = array();
185 191
 		$nondated = array();
186 192
 		//-- split the array into dated and non-dated arrays
@@ -236,7 +242,8 @@  discard block
 block discarded – undo
236 242
 	 *
237 243
 	 * @return string
238 244
 	 */
239
-	public static function getCloseRelationshipName(Individual $individual1, Individual $individual2) {
245
+	public static function getCloseRelationshipName(Individual $individual1, Individual $individual2)
246
+	{
240 247
 		if ($individual1 === $individual2) {
241 248
 			$label = '<i class="icon-selected"></i> ' . self::reflexivePronoun($individual1);
242 249
 		} else {
@@ -254,7 +261,8 @@  discard block
 block discarded – undo
254 261
 	 *
255 262
 	 * @return string
256 263
 	 */
257
-	public static function getAssociateRelationshipName(Individual $individual1, Individual $individual2) {
264
+	public static function getAssociateRelationshipName(Individual $individual1, Individual $individual2)
265
+	{
258 266
 		if ($individual1 === $individual2) {
259 267
 			$label = self::reflexivePronoun($individual1);
260 268
 		} else {
@@ -271,7 +279,8 @@  discard block
 block discarded – undo
271 279
 	 *
272 280
 	 * @return string
273 281
 	 */
274
-	private static function reflexivePronoun(Individual $individual) {
282
+	private static function reflexivePronoun(Individual $individual)
283
+	{
275 284
 		switch ($individual->getSex()) {
276 285
 		case 'M':
277 286
 			return /* I18N: reflexive pronoun */ I18N::translate('himself');
@@ -291,7 +300,8 @@  discard block
 block discarded – undo
291 300
 	 *
292 301
 	 * @return array|bool An array of nodes on the relationship path, or false if no path found
293 302
 	 */
294
-	public static function getRelationship(Individual $person1, Individual $person2, $maxlength = 4) {
303
+	public static function getRelationship(Individual $person1, Individual $person2, $maxlength = 4)
304
+	{
295 305
 		if ($person1 === $person2) {
296 306
 			return false;
297 307
 		}
@@ -423,7 +433,8 @@  discard block
 block discarded – undo
423 433
 	 *
424 434
 	 * @return string
425 435
 	 */
426
-	public static function getRelationshipName($nodes) {
436
+	public static function getRelationshipName($nodes)
437
+	{
427 438
 		if (!is_array($nodes)) {
428 439
 			return '';
429 440
 		}
@@ -461,7 +472,8 @@  discard block
 block discarded – undo
461 472
 	 *
462 473
 	 * @return string
463 474
 	 */
464
-	public static function cousinName($n, $sex) {
475
+	public static function cousinName($n, $sex)
476
+	{
465 477
 		switch ($sex) {
466 478
 		case 'M':
467 479
 			switch ($n) {
@@ -597,7 +609,8 @@  discard block
 block discarded – undo
597 609
 	 *
598 610
 	 * @return string
599 611
 	 */
600
-	public static function cousinName2($n, $sex, $relation) {
612
+	public static function cousinName2($n, $sex, $relation)
613
+	{
601 614
 		switch ($sex) {
602 615
 		case 'M':
603 616
 			switch ($n) {
@@ -659,7 +672,8 @@  discard block
 block discarded – undo
659 672
 	 *
660 673
 	 * @return string
661 674
 	 */
662
-	public static function getRelationshipNameFromPath($path, Individual $person1 = null, Individual $person2 = null) {
675
+	public static function getRelationshipNameFromPath($path, Individual $person1 = null, Individual $person2 = null)
676
+	{
663 677
 		if (!preg_match('/^(mot|fat|par|hus|wif|spo|son|dau|chi|bro|sis|sib)*$/', $path)) {
664 678
 			// TODO: Update all the “3 RELA ” values in class_person
665 679
 			return '<span class="error">' . $path . '</span>';
@@ -2176,7 +2190,8 @@  discard block
 block discarded – undo
2176 2190
 	 *
2177 2191
 	 * @return string
2178 2192
 	 */
2179
-	public static function getQueryUrl($overwrite = null, $separator = '&') {
2193
+	public static function getQueryUrl($overwrite = null, $separator = '&')
2194
+	{
2180 2195
 		if (empty($_GET)) {
2181 2196
 			$get = array();
2182 2197
 		} else {
@@ -2213,7 +2228,8 @@  discard block
 block discarded – undo
2213 2228
 	 *
2214 2229
 	 * @return bool
2215 2230
 	 */
2216
-	public static function isFileExternal($file) {
2231
+	public static function isFileExternal($file)
2232
+	{
2217 2233
 		return strpos($file, '://') !== false;
2218 2234
 	}
2219 2235
 }
Please login to merge, or discard this patch.
app/Functions/FunctionsDate.php 3 patches
Indentation   +99 added lines, -99 removed lines patch added patch discarded remove patch
@@ -22,106 +22,106 @@
 block discarded – undo
22 22
  * Class FunctionsDate - common functions
23 23
  */
24 24
 class FunctionsDate {
25
-	/**
26
-	 * Convert a GEDCOM age string to localized text.
27
-	 *
28
-	 * @param string $age_string
29
-	 *
30
-	 * @return string
31
-	 */
32
-	public static function getAgeAtEvent($age_string) {
33
-		switch (strtoupper($age_string)) {
34
-		case 'CHILD':
35
-			return I18N::translate('Child');
36
-		case 'INFANT':
37
-			return I18N::translate('Infant');
38
-		case 'STILLBORN':
39
-			return I18N::translate('Stillborn');
40
-		default:
41
-			return preg_replace_callback(
42
-				array(
43
-					'/(\d+)([ymwd])/',
44
-				),
45
-				function ($match) {
46
-					switch ($match[2]) {
47
-					case 'y':
48
-						return I18N::plural('%s year', '%s years', $match[1], I18N::digits($match[1]));
49
-					case 'm':
50
-						return I18N::plural('%s month', '%s months', $match[1], I18N::digits($match[1]));
51
-					case 'w':
52
-						return I18N::plural('%s week', '%s weeks', $match[1], I18N::digits($match[1]));
53
-					case 'd':
54
-						return I18N::plural('%s day', '%s days', $match[1], I18N::digits($match[1]));
55
-					}
56
-				},
57
-				$age_string
58
-			);
59
-		}
60
-	}
25
+    /**
26
+     * Convert a GEDCOM age string to localized text.
27
+     *
28
+     * @param string $age_string
29
+     *
30
+     * @return string
31
+     */
32
+    public static function getAgeAtEvent($age_string) {
33
+        switch (strtoupper($age_string)) {
34
+        case 'CHILD':
35
+            return I18N::translate('Child');
36
+        case 'INFANT':
37
+            return I18N::translate('Infant');
38
+        case 'STILLBORN':
39
+            return I18N::translate('Stillborn');
40
+        default:
41
+            return preg_replace_callback(
42
+                array(
43
+                    '/(\d+)([ymwd])/',
44
+                ),
45
+                function ($match) {
46
+                    switch ($match[2]) {
47
+                    case 'y':
48
+                        return I18N::plural('%s year', '%s years', $match[1], I18N::digits($match[1]));
49
+                    case 'm':
50
+                        return I18N::plural('%s month', '%s months', $match[1], I18N::digits($match[1]));
51
+                    case 'w':
52
+                        return I18N::plural('%s week', '%s weeks', $match[1], I18N::digits($match[1]));
53
+                    case 'd':
54
+                        return I18N::plural('%s day', '%s days', $match[1], I18N::digits($match[1]));
55
+                    }
56
+                },
57
+                $age_string
58
+            );
59
+        }
60
+    }
61 61
 
62
-	/**
63
-	 * Convert a unix timestamp into a formatted date-time value, for logs, etc.
64
-	 * Don't attempt to convert into other calendars, as not all days start at
65
-	 * midnight, and we can only get it wrong.
66
-	 *
67
-	 * @param int $time
68
-	 *
69
-	 * @return string
70
-	 */
71
-	public static function formatTimestamp($time) {
72
-		$time_fmt = I18N::timeFormat();
73
-		// PHP::date() doesn't do I18N. Do it ourselves....
74
-		preg_match_all('/%[^%]/', $time_fmt, $matches);
75
-		foreach ($matches[0] as $match) {
76
-			switch ($match) {
77
-			case '%a':
78
-				$t = gmdate('His', $time);
79
-				if ($t == '000000') {
80
-					$time_fmt = str_replace($match, /* I18N: time format “%a” - exactly 00:00:00 */
81
-						I18N::translate('midnight'), $time_fmt);
82
-				} elseif ($t < '120000') {
83
-					$time_fmt = str_replace($match, /* I18N: time format “%a” - between 00:00:01 and 11:59:59 */
84
-						I18N::translate('a.m.'), $time_fmt);
85
-				} elseif ($t == '120000') {
86
-					$time_fmt = str_replace($match, /* I18N: time format “%a” - exactly 12:00:00 */
87
-						I18N::translate('noon'), $time_fmt);
88
-				} else {
89
-					$time_fmt = str_replace($match, /* I18N: time format “%a” - between 12:00:01 and 23:59:59 */
90
-						I18N::translate('p.m.'), $time_fmt);
91
-				}
92
-				break;
93
-			case '%A':
94
-				$t = gmdate('His', $time);
95
-				if ($t == '000000') {
96
-					$time_fmt = str_replace($match, /* I18N: time format “%A” - exactly 00:00:00 */
97
-						I18N::translate('Midnight'), $time_fmt);
98
-				} elseif ($t < '120000') {
99
-					$time_fmt = str_replace($match, /* I18N: time format “%A” - between 00:00:01 and 11:59:59 */
100
-						I18N::translate('A.M.'), $time_fmt);
101
-				} elseif ($t == '120000') {
102
-					$time_fmt = str_replace($match, /* I18N: time format “%A” - exactly 12:00:00 */
103
-						I18N::translate('Noon'), $time_fmt);
104
-				} else {
105
-					$time_fmt = str_replace($match, /* I18N: time format “%A” - between 12:00:01 and 23:59:59 */
106
-						I18N::translate('P.M.'), $time_fmt);
107
-				}
108
-				break;
109
-			default:
110
-				$time_fmt = str_replace($match, I18N::digits(gmdate(substr($match, -1), $time)), $time_fmt);
111
-			}
112
-		}
62
+    /**
63
+     * Convert a unix timestamp into a formatted date-time value, for logs, etc.
64
+     * Don't attempt to convert into other calendars, as not all days start at
65
+     * midnight, and we can only get it wrong.
66
+     *
67
+     * @param int $time
68
+     *
69
+     * @return string
70
+     */
71
+    public static function formatTimestamp($time) {
72
+        $time_fmt = I18N::timeFormat();
73
+        // PHP::date() doesn't do I18N. Do it ourselves....
74
+        preg_match_all('/%[^%]/', $time_fmt, $matches);
75
+        foreach ($matches[0] as $match) {
76
+            switch ($match) {
77
+            case '%a':
78
+                $t = gmdate('His', $time);
79
+                if ($t == '000000') {
80
+                    $time_fmt = str_replace($match, /* I18N: time format “%a” - exactly 00:00:00 */
81
+                        I18N::translate('midnight'), $time_fmt);
82
+                } elseif ($t < '120000') {
83
+                    $time_fmt = str_replace($match, /* I18N: time format “%a” - between 00:00:01 and 11:59:59 */
84
+                        I18N::translate('a.m.'), $time_fmt);
85
+                } elseif ($t == '120000') {
86
+                    $time_fmt = str_replace($match, /* I18N: time format “%a” - exactly 12:00:00 */
87
+                        I18N::translate('noon'), $time_fmt);
88
+                } else {
89
+                    $time_fmt = str_replace($match, /* I18N: time format “%a” - between 12:00:01 and 23:59:59 */
90
+                        I18N::translate('p.m.'), $time_fmt);
91
+                }
92
+                break;
93
+            case '%A':
94
+                $t = gmdate('His', $time);
95
+                if ($t == '000000') {
96
+                    $time_fmt = str_replace($match, /* I18N: time format “%A” - exactly 00:00:00 */
97
+                        I18N::translate('Midnight'), $time_fmt);
98
+                } elseif ($t < '120000') {
99
+                    $time_fmt = str_replace($match, /* I18N: time format “%A” - between 00:00:01 and 11:59:59 */
100
+                        I18N::translate('A.M.'), $time_fmt);
101
+                } elseif ($t == '120000') {
102
+                    $time_fmt = str_replace($match, /* I18N: time format “%A” - exactly 12:00:00 */
103
+                        I18N::translate('Noon'), $time_fmt);
104
+                } else {
105
+                    $time_fmt = str_replace($match, /* I18N: time format “%A” - between 12:00:01 and 23:59:59 */
106
+                        I18N::translate('P.M.'), $time_fmt);
107
+                }
108
+                break;
109
+            default:
110
+                $time_fmt = str_replace($match, I18N::digits(gmdate(substr($match, -1), $time)), $time_fmt);
111
+            }
112
+        }
113 113
 
114
-		return self::timestampToGedcomDate($time)->display() . '<span class="date"> - ' . $time_fmt . '</span>';
115
-	}
114
+        return self::timestampToGedcomDate($time)->display() . '<span class="date"> - ' . $time_fmt . '</span>';
115
+    }
116 116
 
117
-	/**
118
-	 * Convert a unix-style timestamp into a Date object
119
-	 *
120
-	 * @param int $time
121
-	 *
122
-	 * @return Date
123
-	 */
124
-	public static function timestampToGedcomDate($time) {
125
-		return new Date(strtoupper(gmdate('j M Y', $time)));
126
-	}
117
+    /**
118
+     * Convert a unix-style timestamp into a Date object
119
+     *
120
+     * @param int $time
121
+     *
122
+     * @return Date
123
+     */
124
+    public static function timestampToGedcomDate($time) {
125
+        return new Date(strtoupper(gmdate('j M Y', $time)));
126
+    }
127 127
 }
Please login to merge, or discard this patch.
Switch Indentation   +56 added lines, -56 removed lines patch added patch discarded remove patch
@@ -31,28 +31,28 @@  discard block
 block discarded – undo
31 31
 	 */
32 32
 	public static function getAgeAtEvent($age_string) {
33 33
 		switch (strtoupper($age_string)) {
34
-		case 'CHILD':
35
-			return I18N::translate('Child');
36
-		case 'INFANT':
37
-			return I18N::translate('Infant');
38
-		case 'STILLBORN':
39
-			return I18N::translate('Stillborn');
40
-		default:
41
-			return preg_replace_callback(
42
-				array(
43
-					'/(\d+)([ymwd])/',
44
-				),
45
-				function ($match) {
46
-					switch ($match[2]) {
47
-					case 'y':
48
-						return I18N::plural('%s year', '%s years', $match[1], I18N::digits($match[1]));
49
-					case 'm':
50
-						return I18N::plural('%s month', '%s months', $match[1], I18N::digits($match[1]));
51
-					case 'w':
52
-						return I18N::plural('%s week', '%s weeks', $match[1], I18N::digits($match[1]));
53
-					case 'd':
54
-						return I18N::plural('%s day', '%s days', $match[1], I18N::digits($match[1]));
55
-					}
34
+		    case 'CHILD':
35
+			    return I18N::translate('Child');
36
+		    case 'INFANT':
37
+			    return I18N::translate('Infant');
38
+		    case 'STILLBORN':
39
+			    return I18N::translate('Stillborn');
40
+		    default:
41
+			    return preg_replace_callback(
42
+				    array(
43
+					    '/(\d+)([ymwd])/',
44
+				    ),
45
+				    function ($match) {
46
+					    switch ($match[2]) {
47
+					        case 'y':
48
+						        return I18N::plural('%s year', '%s years', $match[1], I18N::digits($match[1]));
49
+					        case 'm':
50
+						        return I18N::plural('%s month', '%s months', $match[1], I18N::digits($match[1]));
51
+					        case 'w':
52
+						        return I18N::plural('%s week', '%s weeks', $match[1], I18N::digits($match[1]));
53
+					        case 'd':
54
+						        return I18N::plural('%s day', '%s days', $match[1], I18N::digits($match[1]));
55
+					    }
56 56
 				},
57 57
 				$age_string
58 58
 			);
@@ -74,40 +74,40 @@  discard block
 block discarded – undo
74 74
 		preg_match_all('/%[^%]/', $time_fmt, $matches);
75 75
 		foreach ($matches[0] as $match) {
76 76
 			switch ($match) {
77
-			case '%a':
78
-				$t = gmdate('His', $time);
79
-				if ($t == '000000') {
80
-					$time_fmt = str_replace($match, /* I18N: time format “%a” - exactly 00:00:00 */
81
-						I18N::translate('midnight'), $time_fmt);
82
-				} elseif ($t < '120000') {
83
-					$time_fmt = str_replace($match, /* I18N: time format “%a” - between 00:00:01 and 11:59:59 */
84
-						I18N::translate('a.m.'), $time_fmt);
85
-				} elseif ($t == '120000') {
86
-					$time_fmt = str_replace($match, /* I18N: time format “%a” - exactly 12:00:00 */
87
-						I18N::translate('noon'), $time_fmt);
88
-				} else {
89
-					$time_fmt = str_replace($match, /* I18N: time format “%a” - between 12:00:01 and 23:59:59 */
90
-						I18N::translate('p.m.'), $time_fmt);
91
-				}
92
-				break;
93
-			case '%A':
94
-				$t = gmdate('His', $time);
95
-				if ($t == '000000') {
96
-					$time_fmt = str_replace($match, /* I18N: time format “%A” - exactly 00:00:00 */
97
-						I18N::translate('Midnight'), $time_fmt);
98
-				} elseif ($t < '120000') {
99
-					$time_fmt = str_replace($match, /* I18N: time format “%A” - between 00:00:01 and 11:59:59 */
100
-						I18N::translate('A.M.'), $time_fmt);
101
-				} elseif ($t == '120000') {
102
-					$time_fmt = str_replace($match, /* I18N: time format “%A” - exactly 12:00:00 */
103
-						I18N::translate('Noon'), $time_fmt);
104
-				} else {
105
-					$time_fmt = str_replace($match, /* I18N: time format “%A” - between 12:00:01 and 23:59:59 */
106
-						I18N::translate('P.M.'), $time_fmt);
107
-				}
108
-				break;
109
-			default:
110
-				$time_fmt = str_replace($match, I18N::digits(gmdate(substr($match, -1), $time)), $time_fmt);
77
+			    case '%a':
78
+				    $t = gmdate('His', $time);
79
+				    if ($t == '000000') {
80
+					    $time_fmt = str_replace($match, /* I18N: time format “%a” - exactly 00:00:00 */
81
+						    I18N::translate('midnight'), $time_fmt);
82
+				    } elseif ($t < '120000') {
83
+					    $time_fmt = str_replace($match, /* I18N: time format “%a” - between 00:00:01 and 11:59:59 */
84
+						    I18N::translate('a.m.'), $time_fmt);
85
+				    } elseif ($t == '120000') {
86
+					    $time_fmt = str_replace($match, /* I18N: time format “%a” - exactly 12:00:00 */
87
+						    I18N::translate('noon'), $time_fmt);
88
+				    } else {
89
+					    $time_fmt = str_replace($match, /* I18N: time format “%a” - between 12:00:01 and 23:59:59 */
90
+						    I18N::translate('p.m.'), $time_fmt);
91
+				    }
92
+				    break;
93
+			    case '%A':
94
+				    $t = gmdate('His', $time);
95
+				    if ($t == '000000') {
96
+					    $time_fmt = str_replace($match, /* I18N: time format “%A” - exactly 00:00:00 */
97
+						    I18N::translate('Midnight'), $time_fmt);
98
+				    } elseif ($t < '120000') {
99
+					    $time_fmt = str_replace($match, /* I18N: time format “%A” - between 00:00:01 and 11:59:59 */
100
+						    I18N::translate('A.M.'), $time_fmt);
101
+				    } elseif ($t == '120000') {
102
+					    $time_fmt = str_replace($match, /* I18N: time format “%A” - exactly 12:00:00 */
103
+						    I18N::translate('Noon'), $time_fmt);
104
+				    } else {
105
+					    $time_fmt = str_replace($match, /* I18N: time format “%A” - between 12:00:01 and 23:59:59 */
106
+						    I18N::translate('P.M.'), $time_fmt);
107
+				    }
108
+				    break;
109
+			    default:
110
+				    $time_fmt = str_replace($match, I18N::digits(gmdate(substr($match, -1), $time)), $time_fmt);
111 111
 			}
112 112
 		}
113 113
 
Please login to merge, or discard this patch.
Braces   +8 added lines, -4 removed lines patch added patch discarded remove patch
@@ -21,7 +21,8 @@  discard block
 block discarded – undo
21 21
 /**
22 22
  * Class FunctionsDate - common functions
23 23
  */
24
-class FunctionsDate {
24
+class FunctionsDate
25
+{
25 26
 	/**
26 27
 	 * Convert a GEDCOM age string to localized text.
27 28
 	 *
@@ -29,7 +30,8 @@  discard block
 block discarded – undo
29 30
 	 *
30 31
 	 * @return string
31 32
 	 */
32
-	public static function getAgeAtEvent($age_string) {
33
+	public static function getAgeAtEvent($age_string)
34
+	{
33 35
 		switch (strtoupper($age_string)) {
34 36
 		case 'CHILD':
35 37
 			return I18N::translate('Child');
@@ -68,7 +70,8 @@  discard block
 block discarded – undo
68 70
 	 *
69 71
 	 * @return string
70 72
 	 */
71
-	public static function formatTimestamp($time) {
73
+	public static function formatTimestamp($time)
74
+	{
72 75
 		$time_fmt = I18N::timeFormat();
73 76
 		// PHP::date() doesn't do I18N. Do it ourselves....
74 77
 		preg_match_all('/%[^%]/', $time_fmt, $matches);
@@ -121,7 +124,8 @@  discard block
 block discarded – undo
121 124
 	 *
122 125
 	 * @return Date
123 126
 	 */
124
-	public static function timestampToGedcomDate($time) {
127
+	public static function timestampToGedcomDate($time)
128
+	{
125 129
 		return new Date(strtoupper(gmdate('j M Y', $time)));
126 130
 	}
127 131
 }
Please login to merge, or discard this patch.
app/Functions/FunctionsDb.php 3 patches
Indentation   +1008 added lines, -1008 removed lines patch added patch discarded remove patch
@@ -39,1012 +39,1012 @@
 block discarded – undo
39 39
  * Class FunctionsDb - common functions
40 40
  */
41 41
 class FunctionsDb {
42
-	/**
43
-	 * Fetch all records linked to a record - when deleting an object, we must
44
-	 * also delete all links to it.
45
-	 *
46
-	 * @param string $xref
47
-	 * @param int $gedcom_id
48
-	 *
49
-	 * @return string[]
50
-	 */
51
-	public static function fetchAllLinks($xref, $gedcom_id) {
52
-		return
53
-			Database::prepare(
54
-				"SELECT l_from FROM `##link` WHERE l_file = ? AND l_to = ?" .
55
-				" UNION " .
56
-				"SELECT xref FROM `##change` WHERE status = 'pending' AND gedcom_id = ? AND new_gedcom LIKE" .
57
-				" CONCAT('%@', ?, '@%') AND new_gedcom NOT LIKE CONCAT('0 @', ?, '@%')"
58
-			)->execute(array(
59
-				$gedcom_id,
60
-				$xref,
61
-				$gedcom_id,
62
-				$xref,
63
-				$xref,
64
-			))->fetchOneColumn();
65
-	}
66
-
67
-	/**
68
-	 * Get a list of all the sources.
69
-	 *
70
-	 * @param Tree $tree
71
-	 *
72
-	 * @return Source[] array
73
-	 */
74
-	public static function getSourceList(Tree $tree) {
75
-		$rows = Database::prepare(
76
-			"SELECT s_id AS xref, s_gedcom AS gedcom FROM `##sources` WHERE s_file = :tree_id"
77
-		)->execute(array(
78
-			'tree_id' => $tree->getTreeId(),
79
-		))->fetchAll();
80
-
81
-		$list = array();
82
-		foreach ($rows as $row) {
83
-			$list[] = Source::getInstance($row->xref, $tree, $row->gedcom);
84
-		}
85
-		$list = array_filter($list, function (Source $x) { return $x->canShowName(); });
86
-		usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
87
-
88
-		return $list;
89
-	}
90
-
91
-	/**
92
-	 * Get a list of all the repositories.
93
-	 *
94
-	 * @param Tree $tree
95
-	 *
96
-	 * @return Repository[] array
97
-	 */
98
-	public static function getRepositoryList(Tree $tree) {
99
-		$rows = Database::prepare(
100
-			"SELECT o_id AS xref, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'REPO' AND o_file = ?"
101
-		)->execute(array(
102
-			$tree->getTreeId(),
103
-		))->fetchAll();
104
-
105
-		$list = array();
106
-		foreach ($rows as $row) {
107
-			$list[] = Repository::getInstance($row->xref, $tree, $row->gedcom);
108
-		}
109
-		$list = array_filter($list, function (Repository $x) { return $x->canShowName(); });
110
-		usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
111
-
112
-		return $list;
113
-	}
114
-
115
-	/**
116
-	 * Get a list of all the shared notes.
117
-	 *
118
-	 * @param Tree $tree
119
-	 *
120
-	 * @return Note[] array
121
-	 */
122
-	public static function getNoteList(Tree $tree) {
123
-		$rows = Database::prepare(
124
-			"SELECT o_id AS xref, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'NOTE' AND o_file = :tree_id"
125
-		)->execute(array(
126
-			'tree_id' => $tree->getTreeId(),
127
-		))->fetchAll();
128
-
129
-		$list = array();
130
-		foreach ($rows as $row) {
131
-			$list[] = Note::getInstance($row->xref, $tree, $row->gedcom);
132
-		}
133
-		$list = array_filter($list, function (Note $x) { return $x->canShowName(); });
134
-		usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
135
-
136
-		return $list;
137
-	}
138
-
139
-	/**
140
-	 * Search all individuals
141
-	 *
142
-	 * @param string[] $query Search terms
143
-	 * @param Tree[] $trees The trees to search
144
-	 *
145
-	 * @return Individual[]
146
-	 */
147
-	public static function searchIndividuals(array $query, array $trees) {
148
-		// Convert the query into a regular expression
149
-		$queryregex = array();
150
-
151
-		$sql  = "SELECT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom FROM `##individuals` WHERE 1";
152
-		$args = array();
153
-
154
-		foreach ($query as $n => $q) {
155
-			$queryregex[] = preg_quote(I18N::strtoupper($q), '/');
156
-			$sql .= " AND i_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
157
-			$args['collate_' . $n] = I18N::collation();
158
-			$args['query_' . $n]   = Filter::escapeLike($q);
159
-		}
160
-
161
-		$sql .= " AND i_file IN (";
162
-		foreach ($trees as $n => $tree) {
163
-			$sql .= $n ? ", " : "";
164
-			$sql .= ":tree_id_" . $n;
165
-			$args['tree_id_' . $n] = $tree->getTreeId();
166
-		}
167
-		$sql .= ")";
168
-
169
-		$list = array();
170
-		$rows = Database::prepare($sql)->execute($args)->fetchAll();
171
-		foreach ($rows as $row) {
172
-			// SQL may have matched on private data or gedcom tags, so check again against privatized data.
173
-			$record = Individual::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
174
-			// Ignore non-genealogy data
175
-			$gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
176
-			// Ignore links and tags
177
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
178
-			// Re-apply the filtering
179
-			$gedrec = I18N::strtoupper($gedrec);
180
-			foreach ($queryregex as $regex) {
181
-				if (!preg_match('/' . $regex . '/', $gedrec)) {
182
-					continue 2;
183
-				}
184
-			}
185
-			$list[] = $record;
186
-		}
187
-		$list = array_filter($list, function (Individual $x) { return $x->canShowName(); });
188
-
189
-		return $list;
190
-	}
191
-
192
-	/**
193
-	 * Search the names of individuals
194
-	 *
195
-	 * @param string[] $query Search terms
196
-	 * @param Tree[] $trees The trees to search
197
-	 *
198
-	 * @return Individual[]
199
-	 */
200
-	public static function searchIndividualNames(array $query, array $trees) {
201
-		$sql  = "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom, n_full FROM `##individuals` JOIN `##name` ON i_id=n_id AND i_file=n_file WHERE 1";
202
-		$args = array();
203
-
204
-		// Convert the query into a SQL expression
205
-		foreach ($query as $n => $q) {
206
-			$sql .= " AND n_full COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
207
-			$args['collate_' . $n] = I18N::collation();
208
-			$args['query_' . $n]   = Filter::escapeLike($q);
209
-		}
210
-
211
-		$sql .= " AND i_file IN (";
212
-		foreach ($trees as $n => $tree) {
213
-			$sql .= $n ? ", " : "";
214
-			$sql .= ":tree_id_" . $n;
215
-			$args['tree_id_' . $n] = $tree->getTreeId();
216
-		}
217
-		$sql .= ")";
218
-		$list = array();
219
-		$rows = Database::prepare($sql)->execute($args)->fetchAll();
220
-		foreach ($rows as $row) {
221
-			$indi = Individual::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
222
-			foreach ($indi->getAllNames() as $num => $name) {
223
-				if ($name['fullNN'] === $row->n_full) {
224
-					$indi->setPrimaryName($num);
225
-					// We need to clone $indi, as we may have multiple references to the
226
-					// same person in this list, and the "primary name" would otherwise
227
-					// be shared amongst all of them.
228
-					$list[] = clone $indi;
229
-					// Only need to match an individual on one name
230
-					break;
231
-				}
232
-			}
233
-		}
234
-		$list = array_filter($list, function (Individual $x) { return $x->canShowName(); });
235
-
236
-		return $list;
237
-	}
238
-
239
-	/**
240
-	 * Search for individuals names/places using phonetic matching
241
-	 *
242
-	 * @param string $soundex
243
-	 * @param string $lastname
244
-	 * @param string $firstname
245
-	 * @param string $place
246
-	 * @param Tree[] $trees
247
-	 *
248
-	 * @return Individual[]
249
-	 */
250
-	public static function searchIndividualsPhonetic($soundex, $lastname, $firstname, $place, array $trees) {
251
-		switch ($soundex) {
252
-		case 'Russell':
253
-			$givn_sdx = Soundex::russell($firstname);
254
-			$surn_sdx = Soundex::russell($lastname);
255
-			$plac_sdx = Soundex::russell($place);
256
-			break;
257
-		case 'DaitchM':
258
-			$givn_sdx = Soundex::daitchMokotoff($firstname);
259
-			$surn_sdx = Soundex::daitchMokotoff($lastname);
260
-			$plac_sdx = Soundex::daitchMokotoff($place);
261
-			break;
262
-		default:
263
-			throw new \DomainException('soundex: ' . $soundex);
264
-		}
265
-
266
-		// Nothing to search for? Return nothing.
267
-		if (!$givn_sdx && !$surn_sdx && !$plac_sdx) {
268
-			return array();
269
-		}
270
-
271
-		$sql  = "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom FROM `##individuals`";
272
-		$args = array();
273
-
274
-		if ($place) {
275
-			$sql .= " JOIN `##placelinks` ON pl_file = i_file AND pl_gid = i_id";
276
-			$sql .= " JOIN `##places` ON p_file = pl_file AND pl_p_id = p_id";
277
-		}
278
-		if ($firstname || $lastname) {
279
-			$sql .= " JOIN `##name` ON i_file=n_file AND i_id=n_id";
280
-		}
281
-		$sql .= " AND i_file IN (";
282
-		foreach ($trees as $n => $tree) {
283
-			$sql .= $n ? ", " : "";
284
-			$sql .= ":tree_id_" . $n;
285
-			$args['tree_id_' . $n] = $tree->getTreeId();
286
-		}
287
-		$sql .= ")";
288
-
289
-		if ($firstname && $givn_sdx) {
290
-			$sql .= " AND (";
291
-			$givn_sdx = explode(':', $givn_sdx);
292
-			foreach ($givn_sdx as $n => $sdx) {
293
-				$sql .= $n ? " OR " : "";
294
-				switch ($soundex) {
295
-				case 'Russell':
296
-					$sql .= "n_soundex_givn_std LIKE CONCAT('%', :given_name_" . $n . ", '%')";
297
-					break;
298
-				case 'DaitchM':
299
-					$sql .= "n_soundex_givn_dm LIKE CONCAT('%', :given_name_" . $n . ", '%')";
300
-					break;
301
-				}
302
-				$args['given_name_' . $n] = $sdx;
303
-			}
304
-			$sql .= ")";
305
-		}
306
-
307
-		if ($lastname && $surn_sdx) {
308
-			$sql .= " AND (";
309
-			$surn_sdx = explode(':', $surn_sdx);
310
-			foreach ($surn_sdx as $n => $sdx) {
311
-				$sql .= $n ? " OR " : "";
312
-				switch ($soundex) {
313
-				case 'Russell':
314
-					$sql .= "n_soundex_surn_std LIKE CONCAT('%', :surname_" . $n . ", '%')";
315
-					break;
316
-				case 'DaitchM':
317
-					$sql .= "n_soundex_surn_dm LIKE CONCAT('%', :surname_" . $n . ", '%')";
318
-					break;
319
-				}
320
-				$args['surname_' . $n] = $sdx;
321
-			}
322
-			$sql .= ")";
323
-		}
324
-
325
-		if ($place && $plac_sdx) {
326
-			$sql .= " AND (";
327
-			$plac_sdx = explode(':', $plac_sdx);
328
-			foreach ($plac_sdx as $n => $sdx) {
329
-				$sql .= $n ? " OR " : "";
330
-				switch ($soundex) {
331
-				case 'Russell':
332
-					$sql .= "p_std_soundex LIKE CONCAT('%', :place_" . $n . ", '%')";
333
-					break;
334
-				case 'DaitchM':
335
-					$sql .= "p_dm_soundex LIKE CONCAT('%', :place_" . $n . ", '%')";
336
-					break;
337
-				}
338
-				$args['place_' . $n] = $sdx;
339
-			}
340
-			$sql .= ")";
341
-		}
342
-
343
-		$list = array();
344
-		$rows = Database::prepare($sql)->execute($args)->fetchAll();
345
-		foreach ($rows as $row) {
346
-			$list[] = Individual::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
347
-		}
348
-		$list = array_filter($list, function (Individual $x) { return $x->canShowName(); });
349
-
350
-		return $list;
351
-	}
352
-
353
-	/**
354
-	 * Search family records
355
-	 *
356
-	 * @param string[] $query Search terms
357
-	 * @param Tree[] $trees The trees to search
358
-	 *
359
-	 * @return Family[]
360
-	 */
361
-	public static function searchFamilies(array $query, array $trees) {
362
-		// Convert the query into a regular expression
363
-		$queryregex = array();
364
-
365
-		$sql  = "SELECT f_id AS xref, f_file AS gedcom_id, f_gedcom AS gedcom FROM `##families` WHERE 1";
366
-		$args = array();
367
-
368
-		foreach ($query as $n => $q) {
369
-			$queryregex[] = preg_quote(I18N::strtoupper($q), '/');
370
-			$sql .= " AND f_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
371
-			$args['collate_' . $n] = I18N::collation();
372
-			$args['query_' . $n]   = Filter::escapeLike($q);
373
-		}
374
-
375
-		$sql .= " AND f_file IN (";
376
-		foreach ($trees as $n => $tree) {
377
-			$sql .= $n ? ", " : "";
378
-			$sql .= ":tree_id_" . $n;
379
-			$args['tree_id_' . $n] = $tree->getTreeId();
380
-		}
381
-		$sql .= ")";
382
-
383
-		$list = array();
384
-		$rows = Database::prepare($sql)->execute($args)->fetchAll();
385
-		foreach ($rows as $row) {
386
-			// SQL may have matched on private data or gedcom tags, so check again against privatized data.
387
-			$record = Family::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
388
-			// Ignore non-genealogy data
389
-			$gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
390
-			// Ignore links and tags
391
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
392
-			// Ignore tags
393
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec);
394
-			// Re-apply the filtering
395
-			$gedrec = I18N::strtoupper($gedrec);
396
-			foreach ($queryregex as $regex) {
397
-				if (!preg_match('/' . $regex . '/', $gedrec)) {
398
-					continue 2;
399
-				}
400
-			}
401
-			$list[] = $record;
402
-		}
403
-		$list = array_filter($list, function (Family $x) { return $x->canShowName(); });
404
-
405
-		return $list;
406
-	}
407
-
408
-	/**
409
-	 * Search the names of the husb/wife in a family
410
-	 *
411
-	 * @param string[] $query Search terms
412
-	 * @param Tree[] $trees The trees to search
413
-	 *
414
-	 * @return Family[]
415
-	 */
416
-	public static function searchFamilyNames(array $query, array $trees) {
417
-		// No query => no results
418
-		if (!$query) {
419
-			return array();
420
-		}
421
-
422
-		$sql =
423
-			"SELECT DISTINCT f_id AS xref, f_file AS gedcom_id, f_gedcom AS gedcom" .
424
-			" FROM `##families`" .
425
-			" LEFT JOIN `##name` husb ON f_husb = husb.n_id AND f_file = husb.n_file" .
426
-			" LEFT JOIN `##name` wife ON f_wife = wife.n_id AND f_file = wife.n_file" .
427
-			" WHERE 1";
428
-		$args = array();
429
-
430
-		foreach ($query as $n => $q) {
431
-			$sql .= " AND (husb.n_full COLLATE :husb_collate_" . $n . " LIKE CONCAT('%', :husb_query_" . $n . ", '%') OR wife.n_full COLLATE :wife_collate_" . $n . " LIKE CONCAT('%', :wife_query_" . $n . ", '%'))";
432
-			$args['husb_collate_' . $n] = I18N::collation();
433
-			$args['husb_query_' . $n]   = Filter::escapeLike($q);
434
-			$args['wife_collate_' . $n] = I18N::collation();
435
-			$args['wife_query_' . $n]   = Filter::escapeLike($q);
436
-		}
437
-
438
-		$sql .= " AND f_file IN (";
439
-		foreach ($trees as $n => $tree) {
440
-			$sql .= $n ? ", " : "";
441
-			$sql .= ":tree_id_" . $n;
442
-			$args['tree_id_' . $n] = $tree->getTreeId();
443
-		}
444
-		$sql .= ")";
445
-
446
-		$list = array();
447
-		$rows = Database::prepare($sql)->execute($args)->fetchAll();
448
-		foreach ($rows as $row) {
449
-			$list[] = Family::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
450
-		}
451
-
452
-		$list = array_filter($list, function (Family $x) use ($query) {
453
-			$name = I18N::strtolower(strip_tags($x->getFullName()));
454
-			foreach ($query as $q) {
455
-				if (stripos($name, I18N::strtolower($q)) === false) {
456
-					return false;
457
-				}
458
-			}
459
-
460
-			return true;
461
-		});
462
-
463
-		return $list;
464
-	}
465
-
466
-	/**
467
-	 * Search the sources
468
-	 *
469
-	 * @param string[] $query Search terms
470
-	 * @param Tree[] $trees The tree to search
471
-	 *
472
-	 * @return Source[]
473
-	 */
474
-	public static function searchSources($query, $trees) {
475
-		// Convert the query into a regular expression
476
-		$queryregex = array();
477
-
478
-		$sql  = "SELECT s_id AS xref, s_file AS gedcom_id, s_gedcom AS gedcom FROM `##sources` WHERE 1";
479
-		$args = array();
480
-
481
-		foreach ($query as $n => $q) {
482
-			$queryregex[] = preg_quote(I18N::strtoupper($q), '/');
483
-			$sql .= " AND s_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
484
-			$args['collate_' . $n] = I18N::collation();
485
-			$args['query_' . $n]   = Filter::escapeLike($q);
486
-		}
487
-
488
-		$sql .= " AND s_file IN (";
489
-		foreach ($trees as $n => $tree) {
490
-			$sql .= $n ? ", " : "";
491
-			$sql .= ":tree_id_" . $n;
492
-			$args['tree_id_' . $n] = $tree->getTreeId();
493
-		}
494
-		$sql .= ")";
495
-
496
-		$list = array();
497
-		$rows = Database::prepare($sql)->execute($args)->fetchAll();
498
-		foreach ($rows as $row) {
499
-			// SQL may have matched on private data or gedcom tags, so check again against privatized data.
500
-			$record = Source::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
501
-			// Ignore non-genealogy data
502
-			$gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
503
-			// Ignore links and tags
504
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
505
-			// Ignore tags
506
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec);
507
-			// Re-apply the filtering
508
-			$gedrec = I18N::strtoupper($gedrec);
509
-			foreach ($queryregex as $regex) {
510
-				if (!preg_match('/' . $regex . '/', $gedrec)) {
511
-					continue 2;
512
-				}
513
-			}
514
-			$list[] = $record;
515
-		}
516
-		$list = array_filter($list, function (Source $x) { return $x->canShowName(); });
517
-
518
-		return $list;
519
-	}
520
-
521
-	/**
522
-	 * Search the shared notes
523
-	 *
524
-	 * @param string[] $query Search terms
525
-	 * @param Tree[] $trees The tree to search
526
-	 *
527
-	 * @return Note[]
528
-	 */
529
-	public static function searchNotes(array $query, array $trees) {
530
-		// Convert the query into a regular expression
531
-		$queryregex = array();
532
-
533
-		$sql  = "SELECT o_id AS xref, o_file AS gedcom_id, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'NOTE'";
534
-		$args = array();
535
-
536
-		foreach ($query as $n => $q) {
537
-			$queryregex[] = preg_quote(I18N::strtoupper($q), '/');
538
-			$sql .= " AND o_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
539
-			$args['collate_' . $n] = I18N::collation();
540
-			$args['query_' . $n]   = Filter::escapeLike($q);
541
-		}
542
-
543
-		$sql .= " AND o_file IN (";
544
-		foreach ($trees as $n => $tree) {
545
-			$sql .= $n ? ", " : "";
546
-			$sql .= ":tree_id_" . $n;
547
-			$args['tree_id_' . $n] = $tree->getTreeId();
548
-		}
549
-		$sql .= ")";
550
-
551
-		$list = array();
552
-		$rows = Database::prepare($sql)->execute($args)->fetchAll();
553
-		foreach ($rows as $row) {
554
-			// SQL may have matched on private data or gedcom tags, so check again against privatized data.
555
-			$record = Note::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
556
-			// Ignore non-genealogy data
557
-			$gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
558
-			// Ignore links and tags
559
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
560
-			// Ignore tags
561
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec);
562
-			// Re-apply the filtering
563
-			$gedrec = I18N::strtoupper($gedrec);
564
-			foreach ($queryregex as $regex) {
565
-				if (!preg_match('/' . $regex . '/', $gedrec)) {
566
-					continue 2;
567
-				}
568
-			}
569
-			$list[] = $record;
570
-		}
571
-		$list = array_filter($list, function (Note $x) { return $x->canShowName(); });
572
-
573
-		return $list;
574
-	}
575
-
576
-	/**
577
-	 * Search the repositories
578
-	 *
579
-	 * @param string[] $query Search terms
580
-	 * @param Tree[] $trees The trees to search
581
-	 *
582
-	 * @return Repository[]
583
-	 */
584
-	public static function searchRepositories(array $query, array $trees) {
585
-		// Convert the query into a regular expression
586
-		$queryregex = array();
587
-
588
-		$sql  = "SELECT o_id AS xref, o_file AS gedcom_id, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'REPO'";
589
-		$args = array();
590
-
591
-		foreach ($query as $n => $q) {
592
-			$queryregex[] = preg_quote(I18N::strtoupper($q), '/');
593
-			$sql .= " AND o_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
594
-			$args['collate_' . $n] = I18N::collation();
595
-			$args['query_' . $n]   = Filter::escapeLike($q);
596
-		}
597
-
598
-		$sql .= " AND o_file IN (";
599
-		foreach ($trees as $n => $tree) {
600
-			$sql .= $n ? ", " : "";
601
-			$sql .= ":tree_id_" . $n;
602
-			$args['tree_id_' . $n] = $tree->getTreeId();
603
-		}
604
-		$sql .= ")";
605
-
606
-		$list = array();
607
-		$rows = Database::prepare($sql)->execute($args)->fetchAll();
608
-		foreach ($rows as $row) {
609
-			// SQL may have matched on private data or gedcom tags, so check again against privatized data.
610
-			$record = Repository::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
611
-			// Ignore non-genealogy data
612
-			$gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
613
-			// Ignore links and tags
614
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
615
-			// Ignore tags
616
-			$gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec);
617
-			// Re-apply the filtering
618
-			$gedrec = I18N::strtoupper($gedrec);
619
-			foreach ($queryregex as $regex) {
620
-				if (!preg_match('/' . $regex . '/', $gedrec)) {
621
-					continue 2;
622
-				}
623
-			}
624
-			$list[] = $record;
625
-		}
626
-		$list = array_filter($list, function (Repository $x) { return $x->canShowName(); });
627
-
628
-		return $list;
629
-	}
630
-
631
-	/**
632
-	 * Find the record for the given rin.
633
-	 *
634
-	 * @param string $rin
635
-	 *
636
-	 * @return string
637
-	 */
638
-	public static function findRin($rin) {
639
-		global $WT_TREE;
640
-
641
-		$xref =
642
-			Database::prepare("SELECT i_id FROM `##individuals` WHERE i_rin=? AND i_file=?")
643
-				->execute(array($rin, $WT_TREE->getTreeId()))
644
-				->fetchOne();
645
-
646
-		return $xref ? $xref : $rin;
647
-	}
648
-
649
-	/**
650
-	 * Get array of common surnames
651
-	 *
652
-	 * This function returns a simple array of the most common surnames
653
-	 * found in the individuals list.
654
-	 *
655
-	 * @deprecated
656
-	 *
657
-	 * @param int $min The number of times a surname must occur before it is added to the array
658
-	 * @param Tree $tree
659
-	 *
660
-	 * @return int[]
661
-	 */
662
-	public static function getCommonSurnames($min, Tree $tree) {
663
-		return self::getTopSurnames($tree->getTreeId(), $min, 0);
664
-	}
665
-
666
-	/**
667
-	 * get the top surnames
668
-	 *
669
-	 * @param int $ged_id fetch surnames from this gedcom
670
-	 * @param int $min only fetch surnames occuring this many times
671
-	 * @param int $max only fetch this number of surnames (0=all)
672
-	 *
673
-	 * @return int[]
674
-	 */
675
-	public static function getTopSurnames($ged_id, $min, $max) {
676
-		// Use n_surn, rather than n_surname, as it is used to generate URLs for
677
-		// the indi-list, etc.
678
-		$max = (int) $max;
679
-		if ($max == 0) {
680
-			return
681
-				Database::prepare(
682
-					"SELECT n_surn, COUNT(n_surn) FROM `##name`" .
683
-					" WHERE n_file = :tree_id AND n_type != '_MARNM' AND n_surn NOT IN ('@N.N.', '')" .
684
-					" GROUP BY n_surn HAVING COUNT(n_surn) >= :min" .
685
-					" ORDER BY 2 DESC"
686
-				)->execute(array(
687
-					'tree_id' => $ged_id,
688
-					'min'     => $min,
689
-				))->fetchAssoc();
690
-		} else {
691
-			return
692
-				Database::prepare(
693
-					"SELECT n_surn, COUNT(n_surn) FROM `##name`" .
694
-					" WHERE n_file = :tree_id AND n_type != '_MARNM' AND n_surn NOT IN ('@N.N.', '')" .
695
-					" GROUP BY n_surn HAVING COUNT(n_surn) >= :min" .
696
-					" ORDER BY 2 DESC" .
697
-					" LIMIT :limit"
698
-				)->execute(array(
699
-					'tree_id' => $ged_id,
700
-					'min'     => $min,
701
-					'limit'   => $max,
702
-				))->fetchAssoc();
703
-		}
704
-	}
705
-
706
-	/**
707
-	 * Get a list of events whose anniversary occured on a given julian day.
708
-	 * Used on the on-this-day/upcoming blocks and the day/month calendar views.
709
-	 *
710
-	 * @param int $jd the julian day
711
-	 * @param string $facts restrict the search to just these facts or leave blank for all
712
-	 * @param Tree $tree the tree to search
713
-	 *
714
-	 * @return Fact[]
715
-	 */
716
-	public static function getAnniversaryEvents($jd, $facts, Tree $tree) {
717
-		$found_facts = array();
718
-		foreach (array(
719
-			new GregorianDate($jd),
720
-			new JulianDate($jd),
721
-			new FrenchDate($jd),
722
-			new JewishDate($jd),
723
-			new HijriDate($jd),
724
-			new JalaliDate($jd),
725
-		 ) as $anniv) {
726
-			// Build a SQL where clause to match anniversaries in the appropriate calendar.
727
-			$ind_sql =
728
-				"SELECT DISTINCT i_id AS xref, i_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact" .
729
-				" FROM `##dates` JOIN `##individuals` ON d_gid = i_id AND d_file = i_file" .
730
-				" WHERE d_type = :type AND d_file = :tree_id";
731
-			$fam_sql =
732
-				"SELECT DISTINCT f_id AS xref, f_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact" .
733
-				" FROM `##dates` JOIN `##families` ON d_gid = f_id AND d_file = f_file" .
734
-				" WHERE d_type = :type AND d_file = :tree_id";
735
-			$args = array(
736
-				'type'    => $anniv->format('%@'),
737
-				'tree_id' => $tree->getTreeId(),
738
-			);
739
-
740
-			$where = "";
741
-			// SIMPLE CASES:
742
-			// a) Non-hebrew anniversaries
743
-			// b) Hebrew months TVT, SHV, IYR, SVN, TMZ, AAV, ELL
744
-			if (!$anniv instanceof JewishDate || in_array($anniv->m, array(1, 5, 6, 9, 10, 11, 12, 13))) {
745
-				// Dates without days go on the first day of the month
746
-				// Dates with invalid days go on the last day of the month
747
-				if ($anniv->d === 1) {
748
-					$where .= " AND d_day <= 1";
749
-				} elseif ($anniv->d === $anniv->daysInMonth()) {
750
-					$where .= " AND d_day >= :day";
751
-					$args['day'] = $anniv->d;
752
-				} else {
753
-					$where .= " AND d_day = :day";
754
-					$args['day'] = $anniv->d;
755
-				}
756
-				$where .= " AND d_mon = :month";
757
-				$args['month'] = $anniv->m;
758
-			} else {
759
-				// SPECIAL CASES:
760
-				switch ($anniv->m) {
761
-				case 2:
762
-					// 29 CSH does not include 30 CSH (but would include an invalid 31 CSH if there were no 30 CSH)
763
-					if ($anniv->d === 1) {
764
-						$where .= " AND d_day <= 1 AND d_mon = 2";
765
-					} elseif ($anniv->d === 30) {
766
-						$where .= " AND d_day >= 30 AND d_mon = 2";
767
-					} elseif ($anniv->d === 29 && $anniv->daysInMonth() === 29) {
768
-						$where .= " AND (d_day = 29 OR d_day > 30) AND d_mon = 2";
769
-					} else {
770
-						$where .= " AND d_day = :day AND d_mon = 2";
771
-						$args['day'] = $anniv->d;
772
-					}
773
-					break;
774
-				case 3:
775
-					// 1 KSL includes 30 CSH (if this year didn’t have 30 CSH)
776
-					// 29 KSL does not include 30 KSL (but would include an invalid 31 KSL if there were no 30 KSL)
777
-					if ($anniv->d === 1) {
778
-						$tmp = new JewishDate(array($anniv->y, 'CSH', 1));
779
-						if ($tmp->daysInMonth() === 29) {
780
-							$where .= " AND (d_day <= 1 AND d_mon = 3 OR d_day = 30 AND d_mon = 2)";
781
-						} else {
782
-							$where .= " AND d_day <= 1 AND d_mon = 3";
783
-						}
784
-					} elseif ($anniv->d === 30) {
785
-						$where .= " AND d_day >= 30 AND d_mon = 3";
786
-					} elseif ($anniv->d == 29 && $anniv->daysInMonth() === 29) {
787
-						$where .= " AND (d_day = 29 OR d_day > 30) AND d_mon = 3";
788
-					} else {
789
-						$where .= " AND d_day = :day AND d_mon = 3";
790
-						$args['day'] = $anniv->d;
791
-					}
792
-					break;
793
-				case 4:
794
-					// 1 TVT includes 30 KSL (if this year didn’t have 30 KSL)
795
-					if ($anniv->d === 1) {
796
-						$tmp = new JewishDate(array($anniv->y, 'KSL', 1));
797
-						if ($tmp->daysInMonth() === 29) {
798
-							$where .= " AND (d_day <=1 AND d_mon = 4 OR d_day = 30 AND d_mon = 3)";
799
-						} else {
800
-							$where .= " AND d_day <= 1 AND d_mon = 4";
801
-						}
802
-					} elseif ($anniv->d === $anniv->daysInMonth()) {
803
-						$where .= " AND d_day >= :day AND d_mon=4";
804
-						$args['day'] = $anniv->d;
805
-					} else {
806
-						$where .= " AND d_day = :day AND d_mon=4";
807
-						$args['day'] = $anniv->d;
808
-					}
809
-					break;
810
-				case 7: // ADS includes ADR (non-leap)
811
-					if ($anniv->d === 1) {
812
-						$where .= " AND d_day <= 1";
813
-					} elseif ($anniv->d === $anniv->daysInMonth()) {
814
-						$where .= " AND d_day >= :day";
815
-						$args['day'] = $anniv->d;
816
-					} else {
817
-						$where .= " AND d_day = :day";
818
-						$args['day'] = $anniv->d;
819
-					}
820
-					$where .= " AND (d_mon = 6 AND MOD(7 * d_year + 1, 19) >= 7 OR d_mon = 7)";
821
-					break;
822
-				case 8: // 1 NSN includes 30 ADR, if this year is non-leap
823
-					if ($anniv->d === 1) {
824
-						if ($anniv->isLeapYear()) {
825
-							$where .= " AND d_day <= 1 AND d_mon = 8";
826
-						} else {
827
-							$where .= " AND (d_day <= 1 AND d_mon = 8 OR d_day = 30 AND d_mon = 6)";
828
-						}
829
-					} elseif ($anniv->d === $anniv->daysInMonth()) {
830
-						$where .= " AND d_day >= :day AND d_mon = 8";
831
-						$args['day'] = $anniv->d;
832
-					} else {
833
-						$where .= " AND d_day = :day AND d_mon = 8";
834
-						$args['day'] = $anniv->d;
835
-					}
836
-					break;
837
-				}
838
-			}
839
-			// Only events in the past (includes dates without a year)
840
-			$where .= " AND d_year <= :year";
841
-			$args['year'] = $anniv->y;
842
-
843
-			if ($facts) {
844
-				// Restrict to certain types of fact
845
-				$where .= " AND d_fact IN (";
846
-				preg_match_all('/([_A-Z]+)/', $facts, $matches);
847
-				foreach ($matches[1] as $n => $fact) {
848
-					$where .= $n ? ", " : "";
849
-					$where .= ":fact_" . $n;
850
-					$args['fact_' . $n] = $fact;
851
-				}
852
-				$where .= ")";
853
-			} else {
854
-				// If no facts specified, get all except these
855
-				$where .= " AND d_fact NOT IN ('CHAN', 'BAPL', 'SLGC', 'SLGS', 'ENDL', 'CENS', 'RESI', '_TODO')";
856
-			}
857
-
858
-			$order_by = " ORDER BY d_day, d_year DESC";
859
-
860
-			// Now fetch these anniversaries
861
-			foreach (array('INDI' => $ind_sql . $where . $order_by, 'FAM' => $fam_sql . $where . $order_by) as $type => $sql) {
862
-				$rows = Database::prepare($sql)->execute($args)->fetchAll();
863
-				foreach ($rows as $row) {
864
-					if ($type === 'INDI') {
865
-						$record = Individual::getInstance($row->xref, $tree, $row->gedcom);
866
-					} else {
867
-						$record = Family::getInstance($row->xref, $tree, $row->gedcom);
868
-					}
869
-					$anniv_date = new Date($row->d_type . ' ' . $row->d_day . ' ' . $row->d_month . ' ' . $row->d_year);
870
-					foreach ($record->getFacts() as $fact) {
871
-						if (($fact->getDate()->minimumDate() == $anniv_date->minimumDate() || $fact->getDate()->maximumDate() == $anniv_date->minimumDate()) && $fact->getTag() === $row->d_fact) {
872
-							$fact->anniv   = $row->d_year === '0' ? 0 : $anniv->y - $row->d_year;
873
-							$found_facts[] = $fact;
874
-						}
875
-					}
876
-				}
877
-			}
878
-		}
879
-
880
-		return $found_facts;
881
-	}
882
-
883
-	/**
884
-	 * Get a list of events which occured during a given date range.
885
-	 *
886
-	 * @param int $jd1 the start range of julian day
887
-	 * @param int $jd2 the end range of julian day
888
-	 * @param string $facts restrict the search to just these facts or leave blank for all
889
-	 * @param Tree $tree the tree to search
890
-	 *
891
-	 * @return Fact[]
892
-	 */
893
-	public static function getCalendarEvents($jd1, $jd2, $facts, Tree $tree) {
894
-		// If no facts specified, get all except these
895
-		$skipfacts = "CHAN,BAPL,SLGC,SLGS,ENDL,CENS,RESI,NOTE,ADDR,OBJE,SOUR,PAGE,DATA,TEXT";
896
-
897
-		$found_facts = array();
898
-
899
-		// Events that start or end during the period
900
-		$where = "WHERE (d_julianday1>={$jd1} AND d_julianday1<={$jd2} OR d_julianday2>={$jd1} AND d_julianday2<={$jd2})";
901
-
902
-		// Restrict to certain types of fact
903
-		if (empty($facts)) {
904
-			$excl_facts = "'" . preg_replace('/\W+/', "','", $skipfacts) . "'";
905
-			$where .= " AND d_fact NOT IN ({$excl_facts})";
906
-		} else {
907
-			$incl_facts = "'" . preg_replace('/\W+/', "','", $facts) . "'";
908
-			$where .= " AND d_fact IN ({$incl_facts})";
909
-		}
910
-		// Only get events from the current gedcom
911
-		$where .= " AND d_file=" . $tree->getTreeId();
912
-
913
-		// Now fetch these events
914
-		$ind_sql = "SELECT d_gid AS xref, i_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact, d_type FROM `##dates`, `##individuals` {$where} AND d_gid=i_id AND d_file=i_file ORDER BY d_julianday1";
915
-		$fam_sql = "SELECT d_gid AS xref, f_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact, d_type FROM `##dates`, `##families`    {$where} AND d_gid=f_id AND d_file=f_file ORDER BY d_julianday1";
916
-		foreach (array('INDI' => $ind_sql, 'FAM' => $fam_sql) as $type => $sql) {
917
-			$rows = Database::prepare($sql)->fetchAll();
918
-			foreach ($rows as $row) {
919
-				if ($type === 'INDI') {
920
-					$record = Individual::getInstance($row->xref, $tree, $row->gedcom);
921
-				} else {
922
-					$record = Family::getInstance($row->xref, $tree, $row->gedcom);
923
-				}
924
-				$anniv_date = new Date($row->d_type . ' ' . $row->d_day . ' ' . $row->d_month . ' ' . $row->d_year);
925
-				foreach ($record->getFacts() as $fact) {
926
-					if (($fact->getDate()->minimumDate() == $anniv_date->minimumDate() || $fact->getDate()->maximumDate() == $anniv_date->minimumDate()) && $fact->getTag() === $row->d_fact) {
927
-						$fact->anniv   = 0;
928
-						$found_facts[] = $fact;
929
-					}
930
-				}
931
-			}
932
-		}
933
-
934
-		return $found_facts;
935
-	}
936
-
937
-	/**
938
-	 * Get the list of current and upcoming events, sorted by anniversary date
939
-	 *
940
-	 * @param int $jd1
941
-	 * @param int $jd2
942
-	 * @param string $events
943
-	 * @param Tree $tree
944
-	 *
945
-	 * @return Fact[]
946
-	 */
947
-	public static function getEventsList($jd1, $jd2, $events, Tree $tree) {
948
-		$found_facts = array();
949
-		for ($jd = $jd1; $jd <= $jd2; ++$jd) {
950
-			$found_facts = array_merge($found_facts, self::getAnniversaryEvents($jd, $events, $tree));
951
-		}
952
-
953
-		return $found_facts;
954
-	}
955
-
956
-	/**
957
-	 * Check if a media file is shared (i.e. used by another gedcom)
958
-	 *
959
-	 * @param string $file_name
960
-	 * @param int $ged_id
961
-	 *
962
-	 * @return bool
963
-	 */
964
-	public static function isMediaUsedInOtherTree($file_name, $ged_id) {
965
-		return
966
-			(bool) Database::prepare("SELECT COUNT(*) FROM `##media` WHERE m_filename LIKE ? AND m_file<>?")
967
-				->execute(array("%{$file_name}", $ged_id))
968
-				->fetchOne();
969
-	}
970
-
971
-	/**
972
-	 * Get the blocks for a specified user.
973
-	 *
974
-	 * @param int $user_id
975
-	 *
976
-	 * @return string[][]
977
-	 */
978
-	public static function getUserBlocks($user_id) {
979
-		global $WT_TREE;
980
-
981
-		$blocks = array('main' => array(), 'side' => array());
982
-		$rows   = Database::prepare(
983
-			"SELECT location, block_id, module_name" .
984
-			" FROM  `##block`" .
985
-			" JOIN  `##module` USING (module_name)" .
986
-			" JOIN  `##module_privacy` USING (module_name)" .
987
-			" WHERE user_id=?" .
988
-			" AND   status='enabled'" .
989
-			" AND   `##module_privacy`.gedcom_id=?" .
990
-			" AND   access_level>=?" .
991
-			" ORDER BY location, block_order"
992
-		)->execute(array($user_id, $WT_TREE->getTreeId(), Auth::accessLevel($WT_TREE)))->fetchAll();
993
-		foreach ($rows as $row) {
994
-			$blocks[$row->location][$row->block_id] = $row->module_name;
995
-		}
996
-
997
-		return $blocks;
998
-	}
999
-
1000
-	/**
1001
-	 * Get the blocks for the specified tree
1002
-	 *
1003
-	 * @param int $gedcom_id
1004
-	 *
1005
-	 * @return string[][]
1006
-	 */
1007
-	public static function getTreeBlocks($gedcom_id) {
1008
-		if ($gedcom_id < 0) {
1009
-			$access_level = Auth::PRIV_NONE;
1010
-		} else {
1011
-			$access_level = Auth::accessLevel(Tree::findById($gedcom_id));
1012
-		}
1013
-
1014
-		$blocks = array('main' => array(), 'side' => array());
1015
-		$rows   = Database::prepare(
1016
-			"SELECT location, block_id, module_name" .
1017
-			" FROM  `##block`" .
1018
-			" JOIN  `##module` USING (module_name)" .
1019
-			" JOIN  `##module_privacy` USING (module_name, gedcom_id)" .
1020
-			" WHERE gedcom_id = :tree_id" .
1021
-			" AND   status='enabled'" .
1022
-			" AND   access_level >= :access_level" .
1023
-			" ORDER BY location, block_order"
1024
-		)->execute(array(
1025
-			'tree_id'      => $gedcom_id,
1026
-			'access_level' => $access_level,
1027
-		))->fetchAll();
1028
-		foreach ($rows as $row) {
1029
-			$blocks[$row->location][$row->block_id] = $row->module_name;
1030
-		}
1031
-
1032
-		return $blocks;
1033
-	}
1034
-
1035
-	/**
1036
-	 * Update favorites after merging records.
1037
-	 *
1038
-	 * @param string $xref_from
1039
-	 * @param string $xref_to
1040
-	 * @param Tree $tree
1041
-	 *
1042
-	 * @return int
1043
-	 */
1044
-	public static function updateFavorites($xref_from, $xref_to, Tree $tree) {
1045
-		return
1046
-			Database::prepare("UPDATE `##favorite` SET xref=? WHERE xref=? AND gedcom_id=?")
1047
-				->execute(array($xref_to, $xref_from, $tree->getTreeId()))
1048
-				->rowCount();
1049
-	}
42
+    /**
43
+     * Fetch all records linked to a record - when deleting an object, we must
44
+     * also delete all links to it.
45
+     *
46
+     * @param string $xref
47
+     * @param int $gedcom_id
48
+     *
49
+     * @return string[]
50
+     */
51
+    public static function fetchAllLinks($xref, $gedcom_id) {
52
+        return
53
+            Database::prepare(
54
+                "SELECT l_from FROM `##link` WHERE l_file = ? AND l_to = ?" .
55
+                " UNION " .
56
+                "SELECT xref FROM `##change` WHERE status = 'pending' AND gedcom_id = ? AND new_gedcom LIKE" .
57
+                " CONCAT('%@', ?, '@%') AND new_gedcom NOT LIKE CONCAT('0 @', ?, '@%')"
58
+            )->execute(array(
59
+                $gedcom_id,
60
+                $xref,
61
+                $gedcom_id,
62
+                $xref,
63
+                $xref,
64
+            ))->fetchOneColumn();
65
+    }
66
+
67
+    /**
68
+     * Get a list of all the sources.
69
+     *
70
+     * @param Tree $tree
71
+     *
72
+     * @return Source[] array
73
+     */
74
+    public static function getSourceList(Tree $tree) {
75
+        $rows = Database::prepare(
76
+            "SELECT s_id AS xref, s_gedcom AS gedcom FROM `##sources` WHERE s_file = :tree_id"
77
+        )->execute(array(
78
+            'tree_id' => $tree->getTreeId(),
79
+        ))->fetchAll();
80
+
81
+        $list = array();
82
+        foreach ($rows as $row) {
83
+            $list[] = Source::getInstance($row->xref, $tree, $row->gedcom);
84
+        }
85
+        $list = array_filter($list, function (Source $x) { return $x->canShowName(); });
86
+        usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
87
+
88
+        return $list;
89
+    }
90
+
91
+    /**
92
+     * Get a list of all the repositories.
93
+     *
94
+     * @param Tree $tree
95
+     *
96
+     * @return Repository[] array
97
+     */
98
+    public static function getRepositoryList(Tree $tree) {
99
+        $rows = Database::prepare(
100
+            "SELECT o_id AS xref, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'REPO' AND o_file = ?"
101
+        )->execute(array(
102
+            $tree->getTreeId(),
103
+        ))->fetchAll();
104
+
105
+        $list = array();
106
+        foreach ($rows as $row) {
107
+            $list[] = Repository::getInstance($row->xref, $tree, $row->gedcom);
108
+        }
109
+        $list = array_filter($list, function (Repository $x) { return $x->canShowName(); });
110
+        usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
111
+
112
+        return $list;
113
+    }
114
+
115
+    /**
116
+     * Get a list of all the shared notes.
117
+     *
118
+     * @param Tree $tree
119
+     *
120
+     * @return Note[] array
121
+     */
122
+    public static function getNoteList(Tree $tree) {
123
+        $rows = Database::prepare(
124
+            "SELECT o_id AS xref, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'NOTE' AND o_file = :tree_id"
125
+        )->execute(array(
126
+            'tree_id' => $tree->getTreeId(),
127
+        ))->fetchAll();
128
+
129
+        $list = array();
130
+        foreach ($rows as $row) {
131
+            $list[] = Note::getInstance($row->xref, $tree, $row->gedcom);
132
+        }
133
+        $list = array_filter($list, function (Note $x) { return $x->canShowName(); });
134
+        usort($list, '\Fisharebest\Webtrees\GedcomRecord::compare');
135
+
136
+        return $list;
137
+    }
138
+
139
+    /**
140
+     * Search all individuals
141
+     *
142
+     * @param string[] $query Search terms
143
+     * @param Tree[] $trees The trees to search
144
+     *
145
+     * @return Individual[]
146
+     */
147
+    public static function searchIndividuals(array $query, array $trees) {
148
+        // Convert the query into a regular expression
149
+        $queryregex = array();
150
+
151
+        $sql  = "SELECT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom FROM `##individuals` WHERE 1";
152
+        $args = array();
153
+
154
+        foreach ($query as $n => $q) {
155
+            $queryregex[] = preg_quote(I18N::strtoupper($q), '/');
156
+            $sql .= " AND i_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
157
+            $args['collate_' . $n] = I18N::collation();
158
+            $args['query_' . $n]   = Filter::escapeLike($q);
159
+        }
160
+
161
+        $sql .= " AND i_file IN (";
162
+        foreach ($trees as $n => $tree) {
163
+            $sql .= $n ? ", " : "";
164
+            $sql .= ":tree_id_" . $n;
165
+            $args['tree_id_' . $n] = $tree->getTreeId();
166
+        }
167
+        $sql .= ")";
168
+
169
+        $list = array();
170
+        $rows = Database::prepare($sql)->execute($args)->fetchAll();
171
+        foreach ($rows as $row) {
172
+            // SQL may have matched on private data or gedcom tags, so check again against privatized data.
173
+            $record = Individual::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
174
+            // Ignore non-genealogy data
175
+            $gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
176
+            // Ignore links and tags
177
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
178
+            // Re-apply the filtering
179
+            $gedrec = I18N::strtoupper($gedrec);
180
+            foreach ($queryregex as $regex) {
181
+                if (!preg_match('/' . $regex . '/', $gedrec)) {
182
+                    continue 2;
183
+                }
184
+            }
185
+            $list[] = $record;
186
+        }
187
+        $list = array_filter($list, function (Individual $x) { return $x->canShowName(); });
188
+
189
+        return $list;
190
+    }
191
+
192
+    /**
193
+     * Search the names of individuals
194
+     *
195
+     * @param string[] $query Search terms
196
+     * @param Tree[] $trees The trees to search
197
+     *
198
+     * @return Individual[]
199
+     */
200
+    public static function searchIndividualNames(array $query, array $trees) {
201
+        $sql  = "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom, n_full FROM `##individuals` JOIN `##name` ON i_id=n_id AND i_file=n_file WHERE 1";
202
+        $args = array();
203
+
204
+        // Convert the query into a SQL expression
205
+        foreach ($query as $n => $q) {
206
+            $sql .= " AND n_full COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
207
+            $args['collate_' . $n] = I18N::collation();
208
+            $args['query_' . $n]   = Filter::escapeLike($q);
209
+        }
210
+
211
+        $sql .= " AND i_file IN (";
212
+        foreach ($trees as $n => $tree) {
213
+            $sql .= $n ? ", " : "";
214
+            $sql .= ":tree_id_" . $n;
215
+            $args['tree_id_' . $n] = $tree->getTreeId();
216
+        }
217
+        $sql .= ")";
218
+        $list = array();
219
+        $rows = Database::prepare($sql)->execute($args)->fetchAll();
220
+        foreach ($rows as $row) {
221
+            $indi = Individual::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
222
+            foreach ($indi->getAllNames() as $num => $name) {
223
+                if ($name['fullNN'] === $row->n_full) {
224
+                    $indi->setPrimaryName($num);
225
+                    // We need to clone $indi, as we may have multiple references to the
226
+                    // same person in this list, and the "primary name" would otherwise
227
+                    // be shared amongst all of them.
228
+                    $list[] = clone $indi;
229
+                    // Only need to match an individual on one name
230
+                    break;
231
+                }
232
+            }
233
+        }
234
+        $list = array_filter($list, function (Individual $x) { return $x->canShowName(); });
235
+
236
+        return $list;
237
+    }
238
+
239
+    /**
240
+     * Search for individuals names/places using phonetic matching
241
+     *
242
+     * @param string $soundex
243
+     * @param string $lastname
244
+     * @param string $firstname
245
+     * @param string $place
246
+     * @param Tree[] $trees
247
+     *
248
+     * @return Individual[]
249
+     */
250
+    public static function searchIndividualsPhonetic($soundex, $lastname, $firstname, $place, array $trees) {
251
+        switch ($soundex) {
252
+        case 'Russell':
253
+            $givn_sdx = Soundex::russell($firstname);
254
+            $surn_sdx = Soundex::russell($lastname);
255
+            $plac_sdx = Soundex::russell($place);
256
+            break;
257
+        case 'DaitchM':
258
+            $givn_sdx = Soundex::daitchMokotoff($firstname);
259
+            $surn_sdx = Soundex::daitchMokotoff($lastname);
260
+            $plac_sdx = Soundex::daitchMokotoff($place);
261
+            break;
262
+        default:
263
+            throw new \DomainException('soundex: ' . $soundex);
264
+        }
265
+
266
+        // Nothing to search for? Return nothing.
267
+        if (!$givn_sdx && !$surn_sdx && !$plac_sdx) {
268
+            return array();
269
+        }
270
+
271
+        $sql  = "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom FROM `##individuals`";
272
+        $args = array();
273
+
274
+        if ($place) {
275
+            $sql .= " JOIN `##placelinks` ON pl_file = i_file AND pl_gid = i_id";
276
+            $sql .= " JOIN `##places` ON p_file = pl_file AND pl_p_id = p_id";
277
+        }
278
+        if ($firstname || $lastname) {
279
+            $sql .= " JOIN `##name` ON i_file=n_file AND i_id=n_id";
280
+        }
281
+        $sql .= " AND i_file IN (";
282
+        foreach ($trees as $n => $tree) {
283
+            $sql .= $n ? ", " : "";
284
+            $sql .= ":tree_id_" . $n;
285
+            $args['tree_id_' . $n] = $tree->getTreeId();
286
+        }
287
+        $sql .= ")";
288
+
289
+        if ($firstname && $givn_sdx) {
290
+            $sql .= " AND (";
291
+            $givn_sdx = explode(':', $givn_sdx);
292
+            foreach ($givn_sdx as $n => $sdx) {
293
+                $sql .= $n ? " OR " : "";
294
+                switch ($soundex) {
295
+                case 'Russell':
296
+                    $sql .= "n_soundex_givn_std LIKE CONCAT('%', :given_name_" . $n . ", '%')";
297
+                    break;
298
+                case 'DaitchM':
299
+                    $sql .= "n_soundex_givn_dm LIKE CONCAT('%', :given_name_" . $n . ", '%')";
300
+                    break;
301
+                }
302
+                $args['given_name_' . $n] = $sdx;
303
+            }
304
+            $sql .= ")";
305
+        }
306
+
307
+        if ($lastname && $surn_sdx) {
308
+            $sql .= " AND (";
309
+            $surn_sdx = explode(':', $surn_sdx);
310
+            foreach ($surn_sdx as $n => $sdx) {
311
+                $sql .= $n ? " OR " : "";
312
+                switch ($soundex) {
313
+                case 'Russell':
314
+                    $sql .= "n_soundex_surn_std LIKE CONCAT('%', :surname_" . $n . ", '%')";
315
+                    break;
316
+                case 'DaitchM':
317
+                    $sql .= "n_soundex_surn_dm LIKE CONCAT('%', :surname_" . $n . ", '%')";
318
+                    break;
319
+                }
320
+                $args['surname_' . $n] = $sdx;
321
+            }
322
+            $sql .= ")";
323
+        }
324
+
325
+        if ($place && $plac_sdx) {
326
+            $sql .= " AND (";
327
+            $plac_sdx = explode(':', $plac_sdx);
328
+            foreach ($plac_sdx as $n => $sdx) {
329
+                $sql .= $n ? " OR " : "";
330
+                switch ($soundex) {
331
+                case 'Russell':
332
+                    $sql .= "p_std_soundex LIKE CONCAT('%', :place_" . $n . ", '%')";
333
+                    break;
334
+                case 'DaitchM':
335
+                    $sql .= "p_dm_soundex LIKE CONCAT('%', :place_" . $n . ", '%')";
336
+                    break;
337
+                }
338
+                $args['place_' . $n] = $sdx;
339
+            }
340
+            $sql .= ")";
341
+        }
342
+
343
+        $list = array();
344
+        $rows = Database::prepare($sql)->execute($args)->fetchAll();
345
+        foreach ($rows as $row) {
346
+            $list[] = Individual::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
347
+        }
348
+        $list = array_filter($list, function (Individual $x) { return $x->canShowName(); });
349
+
350
+        return $list;
351
+    }
352
+
353
+    /**
354
+     * Search family records
355
+     *
356
+     * @param string[] $query Search terms
357
+     * @param Tree[] $trees The trees to search
358
+     *
359
+     * @return Family[]
360
+     */
361
+    public static function searchFamilies(array $query, array $trees) {
362
+        // Convert the query into a regular expression
363
+        $queryregex = array();
364
+
365
+        $sql  = "SELECT f_id AS xref, f_file AS gedcom_id, f_gedcom AS gedcom FROM `##families` WHERE 1";
366
+        $args = array();
367
+
368
+        foreach ($query as $n => $q) {
369
+            $queryregex[] = preg_quote(I18N::strtoupper($q), '/');
370
+            $sql .= " AND f_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
371
+            $args['collate_' . $n] = I18N::collation();
372
+            $args['query_' . $n]   = Filter::escapeLike($q);
373
+        }
374
+
375
+        $sql .= " AND f_file IN (";
376
+        foreach ($trees as $n => $tree) {
377
+            $sql .= $n ? ", " : "";
378
+            $sql .= ":tree_id_" . $n;
379
+            $args['tree_id_' . $n] = $tree->getTreeId();
380
+        }
381
+        $sql .= ")";
382
+
383
+        $list = array();
384
+        $rows = Database::prepare($sql)->execute($args)->fetchAll();
385
+        foreach ($rows as $row) {
386
+            // SQL may have matched on private data or gedcom tags, so check again against privatized data.
387
+            $record = Family::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
388
+            // Ignore non-genealogy data
389
+            $gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
390
+            // Ignore links and tags
391
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
392
+            // Ignore tags
393
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec);
394
+            // Re-apply the filtering
395
+            $gedrec = I18N::strtoupper($gedrec);
396
+            foreach ($queryregex as $regex) {
397
+                if (!preg_match('/' . $regex . '/', $gedrec)) {
398
+                    continue 2;
399
+                }
400
+            }
401
+            $list[] = $record;
402
+        }
403
+        $list = array_filter($list, function (Family $x) { return $x->canShowName(); });
404
+
405
+        return $list;
406
+    }
407
+
408
+    /**
409
+     * Search the names of the husb/wife in a family
410
+     *
411
+     * @param string[] $query Search terms
412
+     * @param Tree[] $trees The trees to search
413
+     *
414
+     * @return Family[]
415
+     */
416
+    public static function searchFamilyNames(array $query, array $trees) {
417
+        // No query => no results
418
+        if (!$query) {
419
+            return array();
420
+        }
421
+
422
+        $sql =
423
+            "SELECT DISTINCT f_id AS xref, f_file AS gedcom_id, f_gedcom AS gedcom" .
424
+            " FROM `##families`" .
425
+            " LEFT JOIN `##name` husb ON f_husb = husb.n_id AND f_file = husb.n_file" .
426
+            " LEFT JOIN `##name` wife ON f_wife = wife.n_id AND f_file = wife.n_file" .
427
+            " WHERE 1";
428
+        $args = array();
429
+
430
+        foreach ($query as $n => $q) {
431
+            $sql .= " AND (husb.n_full COLLATE :husb_collate_" . $n . " LIKE CONCAT('%', :husb_query_" . $n . ", '%') OR wife.n_full COLLATE :wife_collate_" . $n . " LIKE CONCAT('%', :wife_query_" . $n . ", '%'))";
432
+            $args['husb_collate_' . $n] = I18N::collation();
433
+            $args['husb_query_' . $n]   = Filter::escapeLike($q);
434
+            $args['wife_collate_' . $n] = I18N::collation();
435
+            $args['wife_query_' . $n]   = Filter::escapeLike($q);
436
+        }
437
+
438
+        $sql .= " AND f_file IN (";
439
+        foreach ($trees as $n => $tree) {
440
+            $sql .= $n ? ", " : "";
441
+            $sql .= ":tree_id_" . $n;
442
+            $args['tree_id_' . $n] = $tree->getTreeId();
443
+        }
444
+        $sql .= ")";
445
+
446
+        $list = array();
447
+        $rows = Database::prepare($sql)->execute($args)->fetchAll();
448
+        foreach ($rows as $row) {
449
+            $list[] = Family::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
450
+        }
451
+
452
+        $list = array_filter($list, function (Family $x) use ($query) {
453
+            $name = I18N::strtolower(strip_tags($x->getFullName()));
454
+            foreach ($query as $q) {
455
+                if (stripos($name, I18N::strtolower($q)) === false) {
456
+                    return false;
457
+                }
458
+            }
459
+
460
+            return true;
461
+        });
462
+
463
+        return $list;
464
+    }
465
+
466
+    /**
467
+     * Search the sources
468
+     *
469
+     * @param string[] $query Search terms
470
+     * @param Tree[] $trees The tree to search
471
+     *
472
+     * @return Source[]
473
+     */
474
+    public static function searchSources($query, $trees) {
475
+        // Convert the query into a regular expression
476
+        $queryregex = array();
477
+
478
+        $sql  = "SELECT s_id AS xref, s_file AS gedcom_id, s_gedcom AS gedcom FROM `##sources` WHERE 1";
479
+        $args = array();
480
+
481
+        foreach ($query as $n => $q) {
482
+            $queryregex[] = preg_quote(I18N::strtoupper($q), '/');
483
+            $sql .= " AND s_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
484
+            $args['collate_' . $n] = I18N::collation();
485
+            $args['query_' . $n]   = Filter::escapeLike($q);
486
+        }
487
+
488
+        $sql .= " AND s_file IN (";
489
+        foreach ($trees as $n => $tree) {
490
+            $sql .= $n ? ", " : "";
491
+            $sql .= ":tree_id_" . $n;
492
+            $args['tree_id_' . $n] = $tree->getTreeId();
493
+        }
494
+        $sql .= ")";
495
+
496
+        $list = array();
497
+        $rows = Database::prepare($sql)->execute($args)->fetchAll();
498
+        foreach ($rows as $row) {
499
+            // SQL may have matched on private data or gedcom tags, so check again against privatized data.
500
+            $record = Source::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
501
+            // Ignore non-genealogy data
502
+            $gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
503
+            // Ignore links and tags
504
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
505
+            // Ignore tags
506
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec);
507
+            // Re-apply the filtering
508
+            $gedrec = I18N::strtoupper($gedrec);
509
+            foreach ($queryregex as $regex) {
510
+                if (!preg_match('/' . $regex . '/', $gedrec)) {
511
+                    continue 2;
512
+                }
513
+            }
514
+            $list[] = $record;
515
+        }
516
+        $list = array_filter($list, function (Source $x) { return $x->canShowName(); });
517
+
518
+        return $list;
519
+    }
520
+
521
+    /**
522
+     * Search the shared notes
523
+     *
524
+     * @param string[] $query Search terms
525
+     * @param Tree[] $trees The tree to search
526
+     *
527
+     * @return Note[]
528
+     */
529
+    public static function searchNotes(array $query, array $trees) {
530
+        // Convert the query into a regular expression
531
+        $queryregex = array();
532
+
533
+        $sql  = "SELECT o_id AS xref, o_file AS gedcom_id, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'NOTE'";
534
+        $args = array();
535
+
536
+        foreach ($query as $n => $q) {
537
+            $queryregex[] = preg_quote(I18N::strtoupper($q), '/');
538
+            $sql .= " AND o_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
539
+            $args['collate_' . $n] = I18N::collation();
540
+            $args['query_' . $n]   = Filter::escapeLike($q);
541
+        }
542
+
543
+        $sql .= " AND o_file IN (";
544
+        foreach ($trees as $n => $tree) {
545
+            $sql .= $n ? ", " : "";
546
+            $sql .= ":tree_id_" . $n;
547
+            $args['tree_id_' . $n] = $tree->getTreeId();
548
+        }
549
+        $sql .= ")";
550
+
551
+        $list = array();
552
+        $rows = Database::prepare($sql)->execute($args)->fetchAll();
553
+        foreach ($rows as $row) {
554
+            // SQL may have matched on private data or gedcom tags, so check again against privatized data.
555
+            $record = Note::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
556
+            // Ignore non-genealogy data
557
+            $gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
558
+            // Ignore links and tags
559
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
560
+            // Ignore tags
561
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec);
562
+            // Re-apply the filtering
563
+            $gedrec = I18N::strtoupper($gedrec);
564
+            foreach ($queryregex as $regex) {
565
+                if (!preg_match('/' . $regex . '/', $gedrec)) {
566
+                    continue 2;
567
+                }
568
+            }
569
+            $list[] = $record;
570
+        }
571
+        $list = array_filter($list, function (Note $x) { return $x->canShowName(); });
572
+
573
+        return $list;
574
+    }
575
+
576
+    /**
577
+     * Search the repositories
578
+     *
579
+     * @param string[] $query Search terms
580
+     * @param Tree[] $trees The trees to search
581
+     *
582
+     * @return Repository[]
583
+     */
584
+    public static function searchRepositories(array $query, array $trees) {
585
+        // Convert the query into a regular expression
586
+        $queryregex = array();
587
+
588
+        $sql  = "SELECT o_id AS xref, o_file AS gedcom_id, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'REPO'";
589
+        $args = array();
590
+
591
+        foreach ($query as $n => $q) {
592
+            $queryregex[] = preg_quote(I18N::strtoupper($q), '/');
593
+            $sql .= " AND o_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')";
594
+            $args['collate_' . $n] = I18N::collation();
595
+            $args['query_' . $n]   = Filter::escapeLike($q);
596
+        }
597
+
598
+        $sql .= " AND o_file IN (";
599
+        foreach ($trees as $n => $tree) {
600
+            $sql .= $n ? ", " : "";
601
+            $sql .= ":tree_id_" . $n;
602
+            $args['tree_id_' . $n] = $tree->getTreeId();
603
+        }
604
+        $sql .= ")";
605
+
606
+        $list = array();
607
+        $rows = Database::prepare($sql)->execute($args)->fetchAll();
608
+        foreach ($rows as $row) {
609
+            // SQL may have matched on private data or gedcom tags, so check again against privatized data.
610
+            $record = Repository::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom);
611
+            // Ignore non-genealogy data
612
+            $gedrec = preg_replace('/\n\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|RESN) .*/', '', $record->getGedcom());
613
+            // Ignore links and tags
614
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec);
615
+            // Ignore tags
616
+            $gedrec = preg_replace('/\n\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec);
617
+            // Re-apply the filtering
618
+            $gedrec = I18N::strtoupper($gedrec);
619
+            foreach ($queryregex as $regex) {
620
+                if (!preg_match('/' . $regex . '/', $gedrec)) {
621
+                    continue 2;
622
+                }
623
+            }
624
+            $list[] = $record;
625
+        }
626
+        $list = array_filter($list, function (Repository $x) { return $x->canShowName(); });
627
+
628
+        return $list;
629
+    }
630
+
631
+    /**
632
+     * Find the record for the given rin.
633
+     *
634
+     * @param string $rin
635
+     *
636
+     * @return string
637
+     */
638
+    public static function findRin($rin) {
639
+        global $WT_TREE;
640
+
641
+        $xref =
642
+            Database::prepare("SELECT i_id FROM `##individuals` WHERE i_rin=? AND i_file=?")
643
+                ->execute(array($rin, $WT_TREE->getTreeId()))
644
+                ->fetchOne();
645
+
646
+        return $xref ? $xref : $rin;
647
+    }
648
+
649
+    /**
650
+     * Get array of common surnames
651
+     *
652
+     * This function returns a simple array of the most common surnames
653
+     * found in the individuals list.
654
+     *
655
+     * @deprecated
656
+     *
657
+     * @param int $min The number of times a surname must occur before it is added to the array
658
+     * @param Tree $tree
659
+     *
660
+     * @return int[]
661
+     */
662
+    public static function getCommonSurnames($min, Tree $tree) {
663
+        return self::getTopSurnames($tree->getTreeId(), $min, 0);
664
+    }
665
+
666
+    /**
667
+     * get the top surnames
668
+     *
669
+     * @param int $ged_id fetch surnames from this gedcom
670
+     * @param int $min only fetch surnames occuring this many times
671
+     * @param int $max only fetch this number of surnames (0=all)
672
+     *
673
+     * @return int[]
674
+     */
675
+    public static function getTopSurnames($ged_id, $min, $max) {
676
+        // Use n_surn, rather than n_surname, as it is used to generate URLs for
677
+        // the indi-list, etc.
678
+        $max = (int) $max;
679
+        if ($max == 0) {
680
+            return
681
+                Database::prepare(
682
+                    "SELECT n_surn, COUNT(n_surn) FROM `##name`" .
683
+                    " WHERE n_file = :tree_id AND n_type != '_MARNM' AND n_surn NOT IN ('@N.N.', '')" .
684
+                    " GROUP BY n_surn HAVING COUNT(n_surn) >= :min" .
685
+                    " ORDER BY 2 DESC"
686
+                )->execute(array(
687
+                    'tree_id' => $ged_id,
688
+                    'min'     => $min,
689
+                ))->fetchAssoc();
690
+        } else {
691
+            return
692
+                Database::prepare(
693
+                    "SELECT n_surn, COUNT(n_surn) FROM `##name`" .
694
+                    " WHERE n_file = :tree_id AND n_type != '_MARNM' AND n_surn NOT IN ('@N.N.', '')" .
695
+                    " GROUP BY n_surn HAVING COUNT(n_surn) >= :min" .
696
+                    " ORDER BY 2 DESC" .
697
+                    " LIMIT :limit"
698
+                )->execute(array(
699
+                    'tree_id' => $ged_id,
700
+                    'min'     => $min,
701
+                    'limit'   => $max,
702
+                ))->fetchAssoc();
703
+        }
704
+    }
705
+
706
+    /**
707
+     * Get a list of events whose anniversary occured on a given julian day.
708
+     * Used on the on-this-day/upcoming blocks and the day/month calendar views.
709
+     *
710
+     * @param int $jd the julian day
711
+     * @param string $facts restrict the search to just these facts or leave blank for all
712
+     * @param Tree $tree the tree to search
713
+     *
714
+     * @return Fact[]
715
+     */
716
+    public static function getAnniversaryEvents($jd, $facts, Tree $tree) {
717
+        $found_facts = array();
718
+        foreach (array(
719
+            new GregorianDate($jd),
720
+            new JulianDate($jd),
721
+            new FrenchDate($jd),
722
+            new JewishDate($jd),
723
+            new HijriDate($jd),
724
+            new JalaliDate($jd),
725
+            ) as $anniv) {
726
+            // Build a SQL where clause to match anniversaries in the appropriate calendar.
727
+            $ind_sql =
728
+                "SELECT DISTINCT i_id AS xref, i_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact" .
729
+                " FROM `##dates` JOIN `##individuals` ON d_gid = i_id AND d_file = i_file" .
730
+                " WHERE d_type = :type AND d_file = :tree_id";
731
+            $fam_sql =
732
+                "SELECT DISTINCT f_id AS xref, f_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact" .
733
+                " FROM `##dates` JOIN `##families` ON d_gid = f_id AND d_file = f_file" .
734
+                " WHERE d_type = :type AND d_file = :tree_id";
735
+            $args = array(
736
+                'type'    => $anniv->format('%@'),
737
+                'tree_id' => $tree->getTreeId(),
738
+            );
739
+
740
+            $where = "";
741
+            // SIMPLE CASES:
742
+            // a) Non-hebrew anniversaries
743
+            // b) Hebrew months TVT, SHV, IYR, SVN, TMZ, AAV, ELL
744
+            if (!$anniv instanceof JewishDate || in_array($anniv->m, array(1, 5, 6, 9, 10, 11, 12, 13))) {
745
+                // Dates without days go on the first day of the month
746
+                // Dates with invalid days go on the last day of the month
747
+                if ($anniv->d === 1) {
748
+                    $where .= " AND d_day <= 1";
749
+                } elseif ($anniv->d === $anniv->daysInMonth()) {
750
+                    $where .= " AND d_day >= :day";
751
+                    $args['day'] = $anniv->d;
752
+                } else {
753
+                    $where .= " AND d_day = :day";
754
+                    $args['day'] = $anniv->d;
755
+                }
756
+                $where .= " AND d_mon = :month";
757
+                $args['month'] = $anniv->m;
758
+            } else {
759
+                // SPECIAL CASES:
760
+                switch ($anniv->m) {
761
+                case 2:
762
+                    // 29 CSH does not include 30 CSH (but would include an invalid 31 CSH if there were no 30 CSH)
763
+                    if ($anniv->d === 1) {
764
+                        $where .= " AND d_day <= 1 AND d_mon = 2";
765
+                    } elseif ($anniv->d === 30) {
766
+                        $where .= " AND d_day >= 30 AND d_mon = 2";
767
+                    } elseif ($anniv->d === 29 && $anniv->daysInMonth() === 29) {
768
+                        $where .= " AND (d_day = 29 OR d_day > 30) AND d_mon = 2";
769
+                    } else {
770
+                        $where .= " AND d_day = :day AND d_mon = 2";
771
+                        $args['day'] = $anniv->d;
772
+                    }
773
+                    break;
774
+                case 3:
775
+                    // 1 KSL includes 30 CSH (if this year didn’t have 30 CSH)
776
+                    // 29 KSL does not include 30 KSL (but would include an invalid 31 KSL if there were no 30 KSL)
777
+                    if ($anniv->d === 1) {
778
+                        $tmp = new JewishDate(array($anniv->y, 'CSH', 1));
779
+                        if ($tmp->daysInMonth() === 29) {
780
+                            $where .= " AND (d_day <= 1 AND d_mon = 3 OR d_day = 30 AND d_mon = 2)";
781
+                        } else {
782
+                            $where .= " AND d_day <= 1 AND d_mon = 3";
783
+                        }
784
+                    } elseif ($anniv->d === 30) {
785
+                        $where .= " AND d_day >= 30 AND d_mon = 3";
786
+                    } elseif ($anniv->d == 29 && $anniv->daysInMonth() === 29) {
787
+                        $where .= " AND (d_day = 29 OR d_day > 30) AND d_mon = 3";
788
+                    } else {
789
+                        $where .= " AND d_day = :day AND d_mon = 3";
790
+                        $args['day'] = $anniv->d;
791
+                    }
792
+                    break;
793
+                case 4:
794
+                    // 1 TVT includes 30 KSL (if this year didn’t have 30 KSL)
795
+                    if ($anniv->d === 1) {
796
+                        $tmp = new JewishDate(array($anniv->y, 'KSL', 1));
797
+                        if ($tmp->daysInMonth() === 29) {
798
+                            $where .= " AND (d_day <=1 AND d_mon = 4 OR d_day = 30 AND d_mon = 3)";
799
+                        } else {
800
+                            $where .= " AND d_day <= 1 AND d_mon = 4";
801
+                        }
802
+                    } elseif ($anniv->d === $anniv->daysInMonth()) {
803
+                        $where .= " AND d_day >= :day AND d_mon=4";
804
+                        $args['day'] = $anniv->d;
805
+                    } else {
806
+                        $where .= " AND d_day = :day AND d_mon=4";
807
+                        $args['day'] = $anniv->d;
808
+                    }
809
+                    break;
810
+                case 7: // ADS includes ADR (non-leap)
811
+                    if ($anniv->d === 1) {
812
+                        $where .= " AND d_day <= 1";
813
+                    } elseif ($anniv->d === $anniv->daysInMonth()) {
814
+                        $where .= " AND d_day >= :day";
815
+                        $args['day'] = $anniv->d;
816
+                    } else {
817
+                        $where .= " AND d_day = :day";
818
+                        $args['day'] = $anniv->d;
819
+                    }
820
+                    $where .= " AND (d_mon = 6 AND MOD(7 * d_year + 1, 19) >= 7 OR d_mon = 7)";
821
+                    break;
822
+                case 8: // 1 NSN includes 30 ADR, if this year is non-leap
823
+                    if ($anniv->d === 1) {
824
+                        if ($anniv->isLeapYear()) {
825
+                            $where .= " AND d_day <= 1 AND d_mon = 8";
826
+                        } else {
827
+                            $where .= " AND (d_day <= 1 AND d_mon = 8 OR d_day = 30 AND d_mon = 6)";
828
+                        }
829
+                    } elseif ($anniv->d === $anniv->daysInMonth()) {
830
+                        $where .= " AND d_day >= :day AND d_mon = 8";
831
+                        $args['day'] = $anniv->d;
832
+                    } else {
833
+                        $where .= " AND d_day = :day AND d_mon = 8";
834
+                        $args['day'] = $anniv->d;
835
+                    }
836
+                    break;
837
+                }
838
+            }
839
+            // Only events in the past (includes dates without a year)
840
+            $where .= " AND d_year <= :year";
841
+            $args['year'] = $anniv->y;
842
+
843
+            if ($facts) {
844
+                // Restrict to certain types of fact
845
+                $where .= " AND d_fact IN (";
846
+                preg_match_all('/([_A-Z]+)/', $facts, $matches);
847
+                foreach ($matches[1] as $n => $fact) {
848
+                    $where .= $n ? ", " : "";
849
+                    $where .= ":fact_" . $n;
850
+                    $args['fact_' . $n] = $fact;
851
+                }
852
+                $where .= ")";
853
+            } else {
854
+                // If no facts specified, get all except these
855
+                $where .= " AND d_fact NOT IN ('CHAN', 'BAPL', 'SLGC', 'SLGS', 'ENDL', 'CENS', 'RESI', '_TODO')";
856
+            }
857
+
858
+            $order_by = " ORDER BY d_day, d_year DESC";
859
+
860
+            // Now fetch these anniversaries
861
+            foreach (array('INDI' => $ind_sql . $where . $order_by, 'FAM' => $fam_sql . $where . $order_by) as $type => $sql) {
862
+                $rows = Database::prepare($sql)->execute($args)->fetchAll();
863
+                foreach ($rows as $row) {
864
+                    if ($type === 'INDI') {
865
+                        $record = Individual::getInstance($row->xref, $tree, $row->gedcom);
866
+                    } else {
867
+                        $record = Family::getInstance($row->xref, $tree, $row->gedcom);
868
+                    }
869
+                    $anniv_date = new Date($row->d_type . ' ' . $row->d_day . ' ' . $row->d_month . ' ' . $row->d_year);
870
+                    foreach ($record->getFacts() as $fact) {
871
+                        if (($fact->getDate()->minimumDate() == $anniv_date->minimumDate() || $fact->getDate()->maximumDate() == $anniv_date->minimumDate()) && $fact->getTag() === $row->d_fact) {
872
+                            $fact->anniv   = $row->d_year === '0' ? 0 : $anniv->y - $row->d_year;
873
+                            $found_facts[] = $fact;
874
+                        }
875
+                    }
876
+                }
877
+            }
878
+        }
879
+
880
+        return $found_facts;
881
+    }
882
+
883
+    /**
884
+     * Get a list of events which occured during a given date range.
885
+     *
886
+     * @param int $jd1 the start range of julian day
887
+     * @param int $jd2 the end range of julian day
888
+     * @param string $facts restrict the search to just these facts or leave blank for all
889
+     * @param Tree $tree the tree to search
890
+     *
891
+     * @return Fact[]
892
+     */
893
+    public static function getCalendarEvents($jd1, $jd2, $facts, Tree $tree) {
894
+        // If no facts specified, get all except these
895
+        $skipfacts = "CHAN,BAPL,SLGC,SLGS,ENDL,CENS,RESI,NOTE,ADDR,OBJE,SOUR,PAGE,DATA,TEXT";
896
+
897
+        $found_facts = array();
898
+
899
+        // Events that start or end during the period
900
+        $where = "WHERE (d_julianday1>={$jd1} AND d_julianday1<={$jd2} OR d_julianday2>={$jd1} AND d_julianday2<={$jd2})";
901
+
902
+        // Restrict to certain types of fact
903
+        if (empty($facts)) {
904
+            $excl_facts = "'" . preg_replace('/\W+/', "','", $skipfacts) . "'";
905
+            $where .= " AND d_fact NOT IN ({$excl_facts})";
906
+        } else {
907
+            $incl_facts = "'" . preg_replace('/\W+/', "','", $facts) . "'";
908
+            $where .= " AND d_fact IN ({$incl_facts})";
909
+        }
910
+        // Only get events from the current gedcom
911
+        $where .= " AND d_file=" . $tree->getTreeId();
912
+
913
+        // Now fetch these events
914
+        $ind_sql = "SELECT d_gid AS xref, i_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact, d_type FROM `##dates`, `##individuals` {$where} AND d_gid=i_id AND d_file=i_file ORDER BY d_julianday1";
915
+        $fam_sql = "SELECT d_gid AS xref, f_gedcom AS gedcom, d_type, d_day, d_month, d_year, d_fact, d_type FROM `##dates`, `##families`    {$where} AND d_gid=f_id AND d_file=f_file ORDER BY d_julianday1";
916
+        foreach (array('INDI' => $ind_sql, 'FAM' => $fam_sql) as $type => $sql) {
917
+            $rows = Database::prepare($sql)->fetchAll();
918
+            foreach ($rows as $row) {
919
+                if ($type === 'INDI') {
920
+                    $record = Individual::getInstance($row->xref, $tree, $row->gedcom);
921
+                } else {
922
+                    $record = Family::getInstance($row->xref, $tree, $row->gedcom);
923
+                }
924
+                $anniv_date = new Date($row->d_type . ' ' . $row->d_day . ' ' . $row->d_month . ' ' . $row->d_year);
925
+                foreach ($record->getFacts() as $fact) {
926
+                    if (($fact->getDate()->minimumDate() == $anniv_date->minimumDate() || $fact->getDate()->maximumDate() == $anniv_date->minimumDate()) && $fact->getTag() === $row->d_fact) {
927
+                        $fact->anniv   = 0;
928
+                        $found_facts[] = $fact;
929
+                    }
930
+                }
931
+            }
932
+        }
933
+
934
+        return $found_facts;
935
+    }
936
+
937
+    /**
938
+     * Get the list of current and upcoming events, sorted by anniversary date
939
+     *
940
+     * @param int $jd1
941
+     * @param int $jd2
942
+     * @param string $events
943
+     * @param Tree $tree
944
+     *
945
+     * @return Fact[]
946
+     */
947
+    public static function getEventsList($jd1, $jd2, $events, Tree $tree) {
948
+        $found_facts = array();
949
+        for ($jd = $jd1; $jd <= $jd2; ++$jd) {
950
+            $found_facts = array_merge($found_facts, self::getAnniversaryEvents($jd, $events, $tree));
951
+        }
952
+
953
+        return $found_facts;
954
+    }
955
+
956
+    /**
957
+     * Check if a media file is shared (i.e. used by another gedcom)
958
+     *
959
+     * @param string $file_name
960
+     * @param int $ged_id
961
+     *
962
+     * @return bool
963
+     */
964
+    public static function isMediaUsedInOtherTree($file_name, $ged_id) {
965
+        return
966
+            (bool) Database::prepare("SELECT COUNT(*) FROM `##media` WHERE m_filename LIKE ? AND m_file<>?")
967
+                ->execute(array("%{$file_name}", $ged_id))
968
+                ->fetchOne();
969
+    }
970
+
971
+    /**
972
+     * Get the blocks for a specified user.
973
+     *
974
+     * @param int $user_id
975
+     *
976
+     * @return string[][]
977
+     */
978
+    public static function getUserBlocks($user_id) {
979
+        global $WT_TREE;
980
+
981
+        $blocks = array('main' => array(), 'side' => array());
982
+        $rows   = Database::prepare(
983
+            "SELECT location, block_id, module_name" .
984
+            " FROM  `##block`" .
985
+            " JOIN  `##module` USING (module_name)" .
986
+            " JOIN  `##module_privacy` USING (module_name)" .
987
+            " WHERE user_id=?" .
988
+            " AND   status='enabled'" .
989
+            " AND   `##module_privacy`.gedcom_id=?" .
990
+            " AND   access_level>=?" .
991
+            " ORDER BY location, block_order"
992
+        )->execute(array($user_id, $WT_TREE->getTreeId(), Auth::accessLevel($WT_TREE)))->fetchAll();
993
+        foreach ($rows as $row) {
994
+            $blocks[$row->location][$row->block_id] = $row->module_name;
995
+        }
996
+
997
+        return $blocks;
998
+    }
999
+
1000
+    /**
1001
+     * Get the blocks for the specified tree
1002
+     *
1003
+     * @param int $gedcom_id
1004
+     *
1005
+     * @return string[][]
1006
+     */
1007
+    public static function getTreeBlocks($gedcom_id) {
1008
+        if ($gedcom_id < 0) {
1009
+            $access_level = Auth::PRIV_NONE;
1010
+        } else {
1011
+            $access_level = Auth::accessLevel(Tree::findById($gedcom_id));
1012
+        }
1013
+
1014
+        $blocks = array('main' => array(), 'side' => array());
1015
+        $rows   = Database::prepare(
1016
+            "SELECT location, block_id, module_name" .
1017
+            " FROM  `##block`" .
1018
+            " JOIN  `##module` USING (module_name)" .
1019
+            " JOIN  `##module_privacy` USING (module_name, gedcom_id)" .
1020
+            " WHERE gedcom_id = :tree_id" .
1021
+            " AND   status='enabled'" .
1022
+            " AND   access_level >= :access_level" .
1023
+            " ORDER BY location, block_order"
1024
+        )->execute(array(
1025
+            'tree_id'      => $gedcom_id,
1026
+            'access_level' => $access_level,
1027
+        ))->fetchAll();
1028
+        foreach ($rows as $row) {
1029
+            $blocks[$row->location][$row->block_id] = $row->module_name;
1030
+        }
1031
+
1032
+        return $blocks;
1033
+    }
1034
+
1035
+    /**
1036
+     * Update favorites after merging records.
1037
+     *
1038
+     * @param string $xref_from
1039
+     * @param string $xref_to
1040
+     * @param Tree $tree
1041
+     *
1042
+     * @return int
1043
+     */
1044
+    public static function updateFavorites($xref_from, $xref_to, Tree $tree) {
1045
+        return
1046
+            Database::prepare("UPDATE `##favorite` SET xref=? WHERE xref=? AND gedcom_id=?")
1047
+                ->execute(array($xref_to, $xref_from, $tree->getTreeId()))
1048
+                ->rowCount();
1049
+    }
1050 1050
 }
Please login to merge, or discard this patch.
Switch Indentation   +106 added lines, -106 removed lines patch added patch discarded remove patch
@@ -249,18 +249,18 @@  discard block
 block discarded – undo
249 249
 	 */
250 250
 	public static function searchIndividualsPhonetic($soundex, $lastname, $firstname, $place, array $trees) {
251 251
 		switch ($soundex) {
252
-		case 'Russell':
253
-			$givn_sdx = Soundex::russell($firstname);
254
-			$surn_sdx = Soundex::russell($lastname);
255
-			$plac_sdx = Soundex::russell($place);
256
-			break;
257
-		case 'DaitchM':
258
-			$givn_sdx = Soundex::daitchMokotoff($firstname);
259
-			$surn_sdx = Soundex::daitchMokotoff($lastname);
260
-			$plac_sdx = Soundex::daitchMokotoff($place);
261
-			break;
262
-		default:
263
-			throw new \DomainException('soundex: ' . $soundex);
252
+		    case 'Russell':
253
+			    $givn_sdx = Soundex::russell($firstname);
254
+			    $surn_sdx = Soundex::russell($lastname);
255
+			    $plac_sdx = Soundex::russell($place);
256
+			    break;
257
+		    case 'DaitchM':
258
+			    $givn_sdx = Soundex::daitchMokotoff($firstname);
259
+			    $surn_sdx = Soundex::daitchMokotoff($lastname);
260
+			    $plac_sdx = Soundex::daitchMokotoff($place);
261
+			    break;
262
+		    default:
263
+			    throw new \DomainException('soundex: ' . $soundex);
264 264
 		}
265 265
 
266 266
 		// Nothing to search for? Return nothing.
@@ -292,12 +292,12 @@  discard block
 block discarded – undo
292 292
 			foreach ($givn_sdx as $n => $sdx) {
293 293
 				$sql .= $n ? " OR " : "";
294 294
 				switch ($soundex) {
295
-				case 'Russell':
296
-					$sql .= "n_soundex_givn_std LIKE CONCAT('%', :given_name_" . $n . ", '%')";
297
-					break;
298
-				case 'DaitchM':
299
-					$sql .= "n_soundex_givn_dm LIKE CONCAT('%', :given_name_" . $n . ", '%')";
300
-					break;
295
+				    case 'Russell':
296
+					    $sql .= "n_soundex_givn_std LIKE CONCAT('%', :given_name_" . $n . ", '%')";
297
+					    break;
298
+				    case 'DaitchM':
299
+					    $sql .= "n_soundex_givn_dm LIKE CONCAT('%', :given_name_" . $n . ", '%')";
300
+					    break;
301 301
 				}
302 302
 				$args['given_name_' . $n] = $sdx;
303 303
 			}
@@ -310,12 +310,12 @@  discard block
 block discarded – undo
310 310
 			foreach ($surn_sdx as $n => $sdx) {
311 311
 				$sql .= $n ? " OR " : "";
312 312
 				switch ($soundex) {
313
-				case 'Russell':
314
-					$sql .= "n_soundex_surn_std LIKE CONCAT('%', :surname_" . $n . ", '%')";
315
-					break;
316
-				case 'DaitchM':
317
-					$sql .= "n_soundex_surn_dm LIKE CONCAT('%', :surname_" . $n . ", '%')";
318
-					break;
313
+				    case 'Russell':
314
+					    $sql .= "n_soundex_surn_std LIKE CONCAT('%', :surname_" . $n . ", '%')";
315
+					    break;
316
+				    case 'DaitchM':
317
+					    $sql .= "n_soundex_surn_dm LIKE CONCAT('%', :surname_" . $n . ", '%')";
318
+					    break;
319 319
 				}
320 320
 				$args['surname_' . $n] = $sdx;
321 321
 			}
@@ -328,12 +328,12 @@  discard block
 block discarded – undo
328 328
 			foreach ($plac_sdx as $n => $sdx) {
329 329
 				$sql .= $n ? " OR " : "";
330 330
 				switch ($soundex) {
331
-				case 'Russell':
332
-					$sql .= "p_std_soundex LIKE CONCAT('%', :place_" . $n . ", '%')";
333
-					break;
334
-				case 'DaitchM':
335
-					$sql .= "p_dm_soundex LIKE CONCAT('%', :place_" . $n . ", '%')";
336
-					break;
331
+				    case 'Russell':
332
+					    $sql .= "p_std_soundex LIKE CONCAT('%', :place_" . $n . ", '%')";
333
+					    break;
334
+				    case 'DaitchM':
335
+					    $sql .= "p_dm_soundex LIKE CONCAT('%', :place_" . $n . ", '%')";
336
+					    break;
337 337
 				}
338 338
 				$args['place_' . $n] = $sdx;
339 339
 			}
@@ -758,82 +758,82 @@  discard block
 block discarded – undo
758 758
 			} else {
759 759
 				// SPECIAL CASES:
760 760
 				switch ($anniv->m) {
761
-				case 2:
762
-					// 29 CSH does not include 30 CSH (but would include an invalid 31 CSH if there were no 30 CSH)
763
-					if ($anniv->d === 1) {
764
-						$where .= " AND d_day <= 1 AND d_mon = 2";
765
-					} elseif ($anniv->d === 30) {
766
-						$where .= " AND d_day >= 30 AND d_mon = 2";
767
-					} elseif ($anniv->d === 29 && $anniv->daysInMonth() === 29) {
768
-						$where .= " AND (d_day = 29 OR d_day > 30) AND d_mon = 2";
769
-					} else {
770
-						$where .= " AND d_day = :day AND d_mon = 2";
771
-						$args['day'] = $anniv->d;
772
-					}
773
-					break;
774
-				case 3:
775
-					// 1 KSL includes 30 CSH (if this year didn’t have 30 CSH)
776
-					// 29 KSL does not include 30 KSL (but would include an invalid 31 KSL if there were no 30 KSL)
777
-					if ($anniv->d === 1) {
778
-						$tmp = new JewishDate(array($anniv->y, 'CSH', 1));
779
-						if ($tmp->daysInMonth() === 29) {
780
-							$where .= " AND (d_day <= 1 AND d_mon = 3 OR d_day = 30 AND d_mon = 2)";
781
-						} else {
782
-							$where .= " AND d_day <= 1 AND d_mon = 3";
783
-						}
784
-					} elseif ($anniv->d === 30) {
785
-						$where .= " AND d_day >= 30 AND d_mon = 3";
786
-					} elseif ($anniv->d == 29 && $anniv->daysInMonth() === 29) {
787
-						$where .= " AND (d_day = 29 OR d_day > 30) AND d_mon = 3";
788
-					} else {
789
-						$where .= " AND d_day = :day AND d_mon = 3";
790
-						$args['day'] = $anniv->d;
791
-					}
792
-					break;
793
-				case 4:
794
-					// 1 TVT includes 30 KSL (if this year didn’t have 30 KSL)
795
-					if ($anniv->d === 1) {
796
-						$tmp = new JewishDate(array($anniv->y, 'KSL', 1));
797
-						if ($tmp->daysInMonth() === 29) {
798
-							$where .= " AND (d_day <=1 AND d_mon = 4 OR d_day = 30 AND d_mon = 3)";
799
-						} else {
800
-							$where .= " AND d_day <= 1 AND d_mon = 4";
801
-						}
802
-					} elseif ($anniv->d === $anniv->daysInMonth()) {
803
-						$where .= " AND d_day >= :day AND d_mon=4";
804
-						$args['day'] = $anniv->d;
805
-					} else {
806
-						$where .= " AND d_day = :day AND d_mon=4";
807
-						$args['day'] = $anniv->d;
808
-					}
809
-					break;
810
-				case 7: // ADS includes ADR (non-leap)
811
-					if ($anniv->d === 1) {
812
-						$where .= " AND d_day <= 1";
813
-					} elseif ($anniv->d === $anniv->daysInMonth()) {
814
-						$where .= " AND d_day >= :day";
815
-						$args['day'] = $anniv->d;
816
-					} else {
817
-						$where .= " AND d_day = :day";
818
-						$args['day'] = $anniv->d;
819
-					}
820
-					$where .= " AND (d_mon = 6 AND MOD(7 * d_year + 1, 19) >= 7 OR d_mon = 7)";
821
-					break;
822
-				case 8: // 1 NSN includes 30 ADR, if this year is non-leap
823
-					if ($anniv->d === 1) {
824
-						if ($anniv->isLeapYear()) {
825
-							$where .= " AND d_day <= 1 AND d_mon = 8";
826
-						} else {
827
-							$where .= " AND (d_day <= 1 AND d_mon = 8 OR d_day = 30 AND d_mon = 6)";
828
-						}
829
-					} elseif ($anniv->d === $anniv->daysInMonth()) {
830
-						$where .= " AND d_day >= :day AND d_mon = 8";
831
-						$args['day'] = $anniv->d;
832
-					} else {
833
-						$where .= " AND d_day = :day AND d_mon = 8";
834
-						$args['day'] = $anniv->d;
835
-					}
836
-					break;
761
+				    case 2:
762
+					    // 29 CSH does not include 30 CSH (but would include an invalid 31 CSH if there were no 30 CSH)
763
+					    if ($anniv->d === 1) {
764
+						    $where .= " AND d_day <= 1 AND d_mon = 2";
765
+					    } elseif ($anniv->d === 30) {
766
+						    $where .= " AND d_day >= 30 AND d_mon = 2";
767
+					    } elseif ($anniv->d === 29 && $anniv->daysInMonth() === 29) {
768
+						    $where .= " AND (d_day = 29 OR d_day > 30) AND d_mon = 2";
769
+					    } else {
770
+						    $where .= " AND d_day = :day AND d_mon = 2";
771
+						    $args['day'] = $anniv->d;
772
+					    }
773
+					    break;
774
+				    case 3:
775
+					    // 1 KSL includes 30 CSH (if this year didn’t have 30 CSH)
776
+					    // 29 KSL does not include 30 KSL (but would include an invalid 31 KSL if there were no 30 KSL)
777
+					    if ($anniv->d === 1) {
778
+						    $tmp = new JewishDate(array($anniv->y, 'CSH', 1));
779
+						    if ($tmp->daysInMonth() === 29) {
780
+							    $where .= " AND (d_day <= 1 AND d_mon = 3 OR d_day = 30 AND d_mon = 2)";
781
+						    } else {
782
+							    $where .= " AND d_day <= 1 AND d_mon = 3";
783
+						    }
784
+					    } elseif ($anniv->d === 30) {
785
+						    $where .= " AND d_day >= 30 AND d_mon = 3";
786
+					    } elseif ($anniv->d == 29 && $anniv->daysInMonth() === 29) {
787
+						    $where .= " AND (d_day = 29 OR d_day > 30) AND d_mon = 3";
788
+					    } else {
789
+						    $where .= " AND d_day = :day AND d_mon = 3";
790
+						    $args['day'] = $anniv->d;
791
+					    }
792
+					    break;
793
+				    case 4:
794
+					    // 1 TVT includes 30 KSL (if this year didn’t have 30 KSL)
795
+					    if ($anniv->d === 1) {
796
+						    $tmp = new JewishDate(array($anniv->y, 'KSL', 1));
797
+						    if ($tmp->daysInMonth() === 29) {
798
+							    $where .= " AND (d_day <=1 AND d_mon = 4 OR d_day = 30 AND d_mon = 3)";
799
+						    } else {
800
+							    $where .= " AND d_day <= 1 AND d_mon = 4";
801
+						    }
802
+					    } elseif ($anniv->d === $anniv->daysInMonth()) {
803
+						    $where .= " AND d_day >= :day AND d_mon=4";
804
+						    $args['day'] = $anniv->d;
805
+					    } else {
806
+						    $where .= " AND d_day = :day AND d_mon=4";
807
+						    $args['day'] = $anniv->d;
808
+					    }
809
+					    break;
810
+				    case 7: // ADS includes ADR (non-leap)
811
+					    if ($anniv->d === 1) {
812
+						    $where .= " AND d_day <= 1";
813
+					    } elseif ($anniv->d === $anniv->daysInMonth()) {
814
+						    $where .= " AND d_day >= :day";
815
+						    $args['day'] = $anniv->d;
816
+					    } else {
817
+						    $where .= " AND d_day = :day";
818
+						    $args['day'] = $anniv->d;
819
+					    }
820
+					    $where .= " AND (d_mon = 6 AND MOD(7 * d_year + 1, 19) >= 7 OR d_mon = 7)";
821
+					    break;
822
+				    case 8: // 1 NSN includes 30 ADR, if this year is non-leap
823
+					    if ($anniv->d === 1) {
824
+						    if ($anniv->isLeapYear()) {
825
+							    $where .= " AND d_day <= 1 AND d_mon = 8";
826
+						    } else {
827
+							    $where .= " AND (d_day <= 1 AND d_mon = 8 OR d_day = 30 AND d_mon = 6)";
828
+						    }
829
+					    } elseif ($anniv->d === $anniv->daysInMonth()) {
830
+						    $where .= " AND d_day >= :day AND d_mon = 8";
831
+						    $args['day'] = $anniv->d;
832
+					    } else {
833
+						    $where .= " AND d_day = :day AND d_mon = 8";
834
+						    $args['day'] = $anniv->d;
835
+					    }
836
+					    break;
837 837
 				}
838 838
 			}
839 839
 			// Only events in the past (includes dates without a year)
Please login to merge, or discard this patch.
Braces   +46 added lines, -23 removed lines patch added patch discarded remove patch
@@ -38,7 +38,8 @@  discard block
 block discarded – undo
38 38
 /**
39 39
  * Class FunctionsDb - common functions
40 40
  */
41
-class FunctionsDb {
41
+class FunctionsDb
42
+{
42 43
 	/**
43 44
 	 * Fetch all records linked to a record - when deleting an object, we must
44 45
 	 * also delete all links to it.
@@ -48,7 +49,8 @@  discard block
 block discarded – undo
48 49
 	 *
49 50
 	 * @return string[]
50 51
 	 */
51
-	public static function fetchAllLinks($xref, $gedcom_id) {
52
+	public static function fetchAllLinks($xref, $gedcom_id)
53
+	{
52 54
 		return
53 55
 			Database::prepare(
54 56
 				"SELECT l_from FROM `##link` WHERE l_file = ? AND l_to = ?" .
@@ -71,7 +73,8 @@  discard block
 block discarded – undo
71 73
 	 *
72 74
 	 * @return Source[] array
73 75
 	 */
74
-	public static function getSourceList(Tree $tree) {
76
+	public static function getSourceList(Tree $tree)
77
+	{
75 78
 		$rows = Database::prepare(
76 79
 			"SELECT s_id AS xref, s_gedcom AS gedcom FROM `##sources` WHERE s_file = :tree_id"
77 80
 		)->execute(array(
@@ -95,7 +98,8 @@  discard block
 block discarded – undo
95 98
 	 *
96 99
 	 * @return Repository[] array
97 100
 	 */
98
-	public static function getRepositoryList(Tree $tree) {
101
+	public static function getRepositoryList(Tree $tree)
102
+	{
99 103
 		$rows = Database::prepare(
100 104
 			"SELECT o_id AS xref, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'REPO' AND o_file = ?"
101 105
 		)->execute(array(
@@ -119,7 +123,8 @@  discard block
 block discarded – undo
119 123
 	 *
120 124
 	 * @return Note[] array
121 125
 	 */
122
-	public static function getNoteList(Tree $tree) {
126
+	public static function getNoteList(Tree $tree)
127
+	{
123 128
 		$rows = Database::prepare(
124 129
 			"SELECT o_id AS xref, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'NOTE' AND o_file = :tree_id"
125 130
 		)->execute(array(
@@ -144,7 +149,8 @@  discard block
 block discarded – undo
144 149
 	 *
145 150
 	 * @return Individual[]
146 151
 	 */
147
-	public static function searchIndividuals(array $query, array $trees) {
152
+	public static function searchIndividuals(array $query, array $trees)
153
+	{
148 154
 		// Convert the query into a regular expression
149 155
 		$queryregex = array();
150 156
 
@@ -197,7 +203,8 @@  discard block
 block discarded – undo
197 203
 	 *
198 204
 	 * @return Individual[]
199 205
 	 */
200
-	public static function searchIndividualNames(array $query, array $trees) {
206
+	public static function searchIndividualNames(array $query, array $trees)
207
+	{
201 208
 		$sql  = "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom, n_full FROM `##individuals` JOIN `##name` ON i_id=n_id AND i_file=n_file WHERE 1";
202 209
 		$args = array();
203 210
 
@@ -247,7 +254,8 @@  discard block
 block discarded – undo
247 254
 	 *
248 255
 	 * @return Individual[]
249 256
 	 */
250
-	public static function searchIndividualsPhonetic($soundex, $lastname, $firstname, $place, array $trees) {
257
+	public static function searchIndividualsPhonetic($soundex, $lastname, $firstname, $place, array $trees)
258
+	{
251 259
 		switch ($soundex) {
252 260
 		case 'Russell':
253 261
 			$givn_sdx = Soundex::russell($firstname);
@@ -358,7 +366,8 @@  discard block
 block discarded – undo
358 366
 	 *
359 367
 	 * @return Family[]
360 368
 	 */
361
-	public static function searchFamilies(array $query, array $trees) {
369
+	public static function searchFamilies(array $query, array $trees)
370
+	{
362 371
 		// Convert the query into a regular expression
363 372
 		$queryregex = array();
364 373
 
@@ -413,7 +422,8 @@  discard block
 block discarded – undo
413 422
 	 *
414 423
 	 * @return Family[]
415 424
 	 */
416
-	public static function searchFamilyNames(array $query, array $trees) {
425
+	public static function searchFamilyNames(array $query, array $trees)
426
+	{
417 427
 		// No query => no results
418 428
 		if (!$query) {
419 429
 			return array();
@@ -471,7 +481,8 @@  discard block
 block discarded – undo
471 481
 	 *
472 482
 	 * @return Source[]
473 483
 	 */
474
-	public static function searchSources($query, $trees) {
484
+	public static function searchSources($query, $trees)
485
+	{
475 486
 		// Convert the query into a regular expression
476 487
 		$queryregex = array();
477 488
 
@@ -526,7 +537,8 @@  discard block
 block discarded – undo
526 537
 	 *
527 538
 	 * @return Note[]
528 539
 	 */
529
-	public static function searchNotes(array $query, array $trees) {
540
+	public static function searchNotes(array $query, array $trees)
541
+	{
530 542
 		// Convert the query into a regular expression
531 543
 		$queryregex = array();
532 544
 
@@ -581,7 +593,8 @@  discard block
 block discarded – undo
581 593
 	 *
582 594
 	 * @return Repository[]
583 595
 	 */
584
-	public static function searchRepositories(array $query, array $trees) {
596
+	public static function searchRepositories(array $query, array $trees)
597
+	{
585 598
 		// Convert the query into a regular expression
586 599
 		$queryregex = array();
587 600
 
@@ -635,7 +648,8 @@  discard block
 block discarded – undo
635 648
 	 *
636 649
 	 * @return string
637 650
 	 */
638
-	public static function findRin($rin) {
651
+	public static function findRin($rin)
652
+	{
639 653
 		global $WT_TREE;
640 654
 
641 655
 		$xref =
@@ -659,7 +673,8 @@  discard block
 block discarded – undo
659 673
 	 *
660 674
 	 * @return int[]
661 675
 	 */
662
-	public static function getCommonSurnames($min, Tree $tree) {
676
+	public static function getCommonSurnames($min, Tree $tree)
677
+	{
663 678
 		return self::getTopSurnames($tree->getTreeId(), $min, 0);
664 679
 	}
665 680
 
@@ -672,7 +687,8 @@  discard block
 block discarded – undo
672 687
 	 *
673 688
 	 * @return int[]
674 689
 	 */
675
-	public static function getTopSurnames($ged_id, $min, $max) {
690
+	public static function getTopSurnames($ged_id, $min, $max)
691
+	{
676 692
 		// Use n_surn, rather than n_surname, as it is used to generate URLs for
677 693
 		// the indi-list, etc.
678 694
 		$max = (int) $max;
@@ -713,7 +729,8 @@  discard block
 block discarded – undo
713 729
 	 *
714 730
 	 * @return Fact[]
715 731
 	 */
716
-	public static function getAnniversaryEvents($jd, $facts, Tree $tree) {
732
+	public static function getAnniversaryEvents($jd, $facts, Tree $tree)
733
+	{
717 734
 		$found_facts = array();
718 735
 		foreach (array(
719 736
 			new GregorianDate($jd),
@@ -890,7 +907,8 @@  discard block
 block discarded – undo
890 907
 	 *
891 908
 	 * @return Fact[]
892 909
 	 */
893
-	public static function getCalendarEvents($jd1, $jd2, $facts, Tree $tree) {
910
+	public static function getCalendarEvents($jd1, $jd2, $facts, Tree $tree)
911
+	{
894 912
 		// If no facts specified, get all except these
895 913
 		$skipfacts = "CHAN,BAPL,SLGC,SLGS,ENDL,CENS,RESI,NOTE,ADDR,OBJE,SOUR,PAGE,DATA,TEXT";
896 914
 
@@ -944,7 +962,8 @@  discard block
 block discarded – undo
944 962
 	 *
945 963
 	 * @return Fact[]
946 964
 	 */
947
-	public static function getEventsList($jd1, $jd2, $events, Tree $tree) {
965
+	public static function getEventsList($jd1, $jd2, $events, Tree $tree)
966
+	{
948 967
 		$found_facts = array();
949 968
 		for ($jd = $jd1; $jd <= $jd2; ++$jd) {
950 969
 			$found_facts = array_merge($found_facts, self::getAnniversaryEvents($jd, $events, $tree));
@@ -961,7 +980,8 @@  discard block
 block discarded – undo
961 980
 	 *
962 981
 	 * @return bool
963 982
 	 */
964
-	public static function isMediaUsedInOtherTree($file_name, $ged_id) {
983
+	public static function isMediaUsedInOtherTree($file_name, $ged_id)
984
+	{
965 985
 		return
966 986
 			(bool) Database::prepare("SELECT COUNT(*) FROM `##media` WHERE m_filename LIKE ? AND m_file<>?")
967 987
 				->execute(array("%{$file_name}", $ged_id))
@@ -975,7 +995,8 @@  discard block
 block discarded – undo
975 995
 	 *
976 996
 	 * @return string[][]
977 997
 	 */
978
-	public static function getUserBlocks($user_id) {
998
+	public static function getUserBlocks($user_id)
999
+	{
979 1000
 		global $WT_TREE;
980 1001
 
981 1002
 		$blocks = array('main' => array(), 'side' => array());
@@ -1004,7 +1025,8 @@  discard block
 block discarded – undo
1004 1025
 	 *
1005 1026
 	 * @return string[][]
1006 1027
 	 */
1007
-	public static function getTreeBlocks($gedcom_id) {
1028
+	public static function getTreeBlocks($gedcom_id)
1029
+	{
1008 1030
 		if ($gedcom_id < 0) {
1009 1031
 			$access_level = Auth::PRIV_NONE;
1010 1032
 		} else {
@@ -1041,7 +1063,8 @@  discard block
 block discarded – undo
1041 1063
 	 *
1042 1064
 	 * @return int
1043 1065
 	 */
1044
-	public static function updateFavorites($xref_from, $xref_to, Tree $tree) {
1066
+	public static function updateFavorites($xref_from, $xref_to, Tree $tree)
1067
+	{
1045 1068
 		return
1046 1069
 			Database::prepare("UPDATE `##favorite` SET xref=? WHERE xref=? AND gedcom_id=?")
1047 1070
 				->execute(array($xref_to, $xref_from, $tree->getTreeId()))
Please login to merge, or discard this patch.