/**
  * Generate the likely value of this census column, based on available information.
  *
  * @param Individual      $individual
  * @param Individual|null $head
  *
  * @return string
  */
 public function generate(Individual $individual, Individual $head = null)
 {
     foreach ($individual->getSpouseFamilies() as $family) {
         foreach ($family->getFacts('MARR') as $fact) {
             if ($fact->getDate()->julianDay() + 365 >= $this->date()->julianDay()) {
                 return 'Y';
             }
         }
     }
     return '';
 }
 /**
  * Generate the likely value of this census column, based on available information.
  *
  * @param Individual      $individual
  * @param Individual|null $head
  *
  * @return string
  */
 public function generate(Individual $individual, Individual $head = null)
 {
     foreach ($individual->getSpouseFamilies() as $family) {
         foreach ($family->getFacts('MARR') as $fact) {
             if ($fact->getDate()->julianDay() + 365 >= $this->date()->julianDay()) {
                 // Use the GEDCOM month, as we need this in English - for the US census
                 return ucfirst(strtolower($fact->getDate()->minimumDate()->format('%O')));
             }
         }
     }
     return '';
 }
Exemplo n.º 3
0
 /**
  * Generate the likely value of this census column, based on available information.
  *
  * @param Individual      $individual
  * @param Individual|null $head
  *
  * @return string
  */
 public function generate(Individual $individual, Individual $head = null)
 {
     if ($individual->getBirthDate()->isOK()) {
         foreach ($individual->getSpouseFamilies() as $family) {
             foreach ($family->getFacts('MARR', true) as $fact) {
                 if ($fact->getDate()->isOK()) {
                     return Date::getAge($individual->getBirthDate(), $fact->getDate(), 0);
                 }
             }
         }
     }
     return '';
 }
 /**
  * Generate the likely value of this census column, based on available information.
  *
  * @param Individual      $individual
  * @param Individual|null $head
  *
  * @return string
  */
 public function generate(Individual $individual, Individual $head = null)
 {
     if ($individual->getSex() !== 'F') {
         return '';
     }
     $count = 0;
     foreach ($individual->getSpouseFamilies() as $family) {
         foreach ($family->getChildren() as $child) {
             if ($child->getBirthDate()->isOK() && Date::compare($child->getBirthDate(), $this->date()) < 0 && $child->getBirthDate() != $child->getDeathDate() && (!$child->getDeathDate()->isOK() || Date::compare($child->getDeathDate(), $this->date()) > 0)) {
                 $count++;
             }
         }
     }
     return (string) $count;
 }
 /**
  * Generate the likely value of this census column, based on available information.
  *
  * @param Individual      $individual
  * @param Individual|null $head
  *
  * @return string
  */
 public function generate(Individual $individual, Individual $head = null)
 {
     $marriage_date = null;
     foreach ($individual->getSpouseFamilies() as $family) {
         foreach ($family->getFacts('MARR', true) as $fact) {
             if ($fact->getDate()->isOK() && Date::compare($fact->getDate(), $this->date()) <= 0) {
                 $marriage_date = $fact->getDate();
             }
         }
     }
     if ($marriage_date === null) {
         return '';
     } else {
         return (string) Date::getAge($marriage_date, $this->date(), 0);
     }
 }
Exemplo n.º 6
0
 /**
  * What was an individual's likely name on a given date, allowing
  * for marriages and married names.
  *
  * @param Individual $individual
  * @param Date       $census_date
  *
  * @return string[]
  */
 protected function nameAtCensusDate(Individual $individual, Date $census_date)
 {
     $names = $individual->getAllNames();
     $name = $names[0];
     foreach ($individual->getSpouseFamilies() as $family) {
         foreach ($family->getFacts('MARR') as $marriage) {
             if ($marriage->getDate()->isOK() && Date::compare($marriage->getDate(), $census_date) < 0) {
                 $spouse = $family->getSpouse($individual);
                 foreach ($names as $individual_name) {
                     foreach ($spouse->getAllNames() as $spouse_name) {
                         if ($individual_name['type'] === '_MARNM' && $individual_name['surn'] === $spouse_name['surn']) {
                             return $individual_name;
                         }
                     }
                 }
             }
         }
     }
     return $name;
 }
Exemplo n.º 7
0
 /**
  * Summary of LDS ordinances.
  *
  * @param Individual $individual
  *
  * @return string
  */
 public static function getLdsSummary(Individual $individual)
 {
     $BAPL = $individual->getFacts('BAPL') ? 'B' : '_';
     $ENDL = $individual->getFacts('ENDL') ? 'E' : '_';
     $SLGC = $individual->getFacts('SLGC') ? 'C' : '_';
     $SLGS = '_';
     foreach ($individual->getSpouseFamilies() as $family) {
         if ($family->getFacts('SLGS')) {
             $SLGS = '';
         }
     }
     return $BAPL . $ENDL . $SLGS . $SLGC;
 }
Exemplo n.º 8
0
    /**
     * Build a map for an individual.
     *
     * @param Individual $indi
     */
    private function buildIndividualMap(Individual $indi)
    {
        $GM_MAX_ZOOM = $this->getSetting('GM_MAX_ZOOM');
        $indifacts = $indi->getFacts();
        foreach ($indi->getSpouseFamilies() as $family) {
            $indifacts = array_merge($indifacts, $family->getFacts());
        }
        Functions::sortFacts($indifacts);
        // Create the markers list array
        $gmarks = array();
        $i = 0;
        foreach ($indifacts as $fact) {
            if (!$fact->getPlace()->isEmpty()) {
                $ctla = preg_match("/\\d LATI (.*)/", $fact->getGedcom(), $match1);
                $ctlo = preg_match("/\\d LONG (.*)/", $fact->getGedcom(), $match2);
                if ($fact->getParent() instanceof Family) {
                    $spouse = $fact->getParent()->getSpouse($indi);
                } else {
                    $spouse = null;
                }
                if ($ctla && $ctlo) {
                    $i++;
                    $gmarks[$i] = array('class' => 'optionbox', 'date' => $fact->getDate()->display(true), 'fact_label' => $fact->getLabel(), 'image' => $spouse ? $spouse->displayImage() : Theme::theme()->icon($fact), 'info' => $fact->getValue(), 'lat' => str_replace(array('N', 'S', ','), array('', '-', '.'), $match1[1]), 'lng' => str_replace(array('E', 'W', ','), array('', '-', '.'), $match2[1]), 'name' => $spouse ? '<a href="' . $spouse->getHtmlUrl() . '"' . $spouse->getFullName() . '</a>' : '', 'pl_icon' => '', 'place' => $fact->getPlace()->getFullName(), 'sv_bearing' => '0', 'sv_elevation' => '0', 'sv_lati' => '0', 'sv_long' => '0', 'sv_zoom' => '0', 'tooltip' => $fact->getPlace()->getGedcomName());
                } else {
                    $latlongval = $this->getLatitudeAndLongitudeFromPlaceLocation($fact->getPlace()->getGedcomName());
                    if ($latlongval && $latlongval->pl_lati && $latlongval->pl_long) {
                        $i++;
                        $gmarks[$i] = array('class' => 'optionbox', 'date' => $fact->getDate()->display(true), 'fact_label' => $fact->getLabel(), 'image' => $spouse ? $spouse->displayImage() : Theme::theme()->icon($fact), 'info' => $fact->getValue(), 'lat' => str_replace(array('N', 'S', ','), array('', '-', '.'), $latlongval->pl_lati), 'lng' => str_replace(array('E', 'W', ','), array('', '-', '.'), $latlongval->pl_long), 'name' => $spouse ? '<a href="' . $spouse->getHtmlUrl() . '"' . $spouse->getFullName() . '</a>' : '', 'pl_icon' => $latlongval->pl_icon, 'place' => $fact->getPlace()->getFullName(), 'sv_bearing' => $latlongval->sv_bearing, 'sv_elevation' => $latlongval->sv_elevation, 'sv_lati' => $latlongval->sv_lati, 'sv_long' => $latlongval->sv_long, 'sv_zoom' => $latlongval->sv_zoom, 'tooltip' => $fact->getPlace()->getGedcomName());
                        if ($GM_MAX_ZOOM > $latlongval->pl_zoom) {
                            $GM_MAX_ZOOM = $latlongval->pl_zoom;
                        }
                    }
                }
            }
        }
        // Add children to the markers list array
        foreach ($indi->getSpouseFamilies() as $family) {
            foreach ($family->getChildren() as $child) {
                $birth = $child->getFirstFact('BIRT');
                if ($birth) {
                    $birthrec = $birth->getGedcom();
                    if (!$birth->getPlace()->isEmpty()) {
                        $ctla = preg_match('/\\n4 LATI (.+)/', $birthrec, $match1);
                        $ctlo = preg_match('/\\n4 LONG (.+)/', $birthrec, $match2);
                        if ($ctla && $ctlo) {
                            $i++;
                            $gmarks[$i] = array('date' => $birth->getDate()->display(true), 'image' => $child->displayImage(), 'info' => '', 'lat' => str_replace(array('N', 'S', ','), array('', '-', '.'), $match1[1]), 'lng' => str_replace(array('E', 'W', ','), array('', '-', '.'), $match2[1]), 'name' => '<a href="' . $child->getHtmlUrl() . '"' . $child->getFullName() . '</a>', 'pl_icon' => '', 'place' => $birth->getPlace()->getFullName(), 'sv_bearing' => '0', 'sv_elevation' => '0', 'sv_lati' => '0', 'sv_long' => '0', 'sv_zoom' => '0', 'tooltip' => $birth->getPlace()->getGedcomName());
                            switch ($child->getSex()) {
                                case 'F':
                                    $gmarks[$i]['fact_label'] = I18N::translate('daughter');
                                    $gmarks[$i]['class'] = 'person_boxF';
                                    break;
                                case 'M':
                                    $gmarks[$i]['fact_label'] = I18N::translate('son');
                                    $gmarks[$i]['class'] = 'person_box';
                                    break;
                                default:
                                    $gmarks[$i]['fact_label'] = I18N::translate('child');
                                    $gmarks[$i]['class'] = 'person_boxNN';
                                    break;
                            }
                        } else {
                            $latlongval = $this->getLatitudeAndLongitudeFromPlaceLocation($birth->getPlace()->getGedcomName());
                            if ($latlongval && $latlongval->pl_lati && $latlongval->pl_long) {
                                $i++;
                                $gmarks[$i] = array('date' => $birth->getDate()->display(true), 'image' => $child->displayImage(), 'info' => '', 'lat' => str_replace(array('N', 'S', ','), array('', '-', '.'), $latlongval->pl_lati), 'lng' => str_replace(array('E', 'W', ','), array('', '-', '.'), $latlongval->pl_long), 'name' => '<a href="' . $child->getHtmlUrl() . '"' . $child->getFullName() . '</a>', 'pl_icon' => $latlongval->pl_icon, 'place' => $birth->getPlace()->getFullName(), 'sv_bearing' => $latlongval->sv_bearing, 'sv_elevation' => $latlongval->sv_elevation, 'sv_lati' => $latlongval->sv_lati, 'sv_long' => $latlongval->sv_long, 'sv_zoom' => $latlongval->sv_zoom, 'tooltip' => $birth->getPlace()->getGedcomName());
                                switch ($child->getSex()) {
                                    case 'M':
                                        $gmarks[$i]['fact_label'] = I18N::translate('son');
                                        $gmarks[$i]['class'] = 'person_box';
                                        break;
                                    case 'F':
                                        $gmarks[$i]['fact_label'] = I18N::translate('daughter');
                                        $gmarks[$i]['class'] = 'person_boxF';
                                        break;
                                    default:
                                        $gmarks[$i]['fact_label'] = I18N::translate('child');
                                        $gmarks[$i]['class'] = 'option_boxNN';
                                        break;
                                }
                                if ($GM_MAX_ZOOM > $latlongval->pl_zoom) {
                                    $GM_MAX_ZOOM = $latlongval->pl_zoom;
                                }
                            }
                        }
                    }
                }
            }
        }
        // *** ENABLE STREETVIEW ***
        $STREETVIEW = $this->getSetting('GM_USE_STREETVIEW');
        ?>

		<script>
			// this variable will collect the html which will eventually be placed in the side_bar
			var side_bar_html = '';
			var map_center = new google.maps.LatLng(0,0);
			var gmarkers = [];
			var gicons = [];
			var map = null;
			var head = '';
			var dir = '';
			var svzoom = '';

			var infowindow = new google.maps.InfoWindow({});

			gicons["red"] = new google.maps.MarkerImage("https://maps.google.com/mapfiles/marker.png",
				new google.maps.Size(20, 34),
				new google.maps.Point(0,0),
				new google.maps.Point(9, 34)
			);

			var iconImage = new google.maps.MarkerImage("https://maps.google.com/mapfiles/marker.png",
				new google.maps.Size(20, 34),
				new google.maps.Point(0,0),
				new google.maps.Point(9, 34)
			);

			var iconShadow = new google.maps.MarkerImage("https://www.google.com/mapfiles/shadow50.png",
				new google.maps.Size(37, 34),
				new google.maps.Point(0,0),
				new google.maps.Point(9, 34)
			);

			var iconShape = {
				coord: [9,0,6,1,4,2,2,4,0,8,0,12,1,14,2,16,5,19,7,23,8,26,9,30,9,34,11,34,11,30,12,26,13,24,14,21,16,18,18,16,20,12,20,8,18,4,16,2,15,1,13,0],
				type: "poly"
			};

			function getMarkerImage(iconColor) {
				if (typeof(iconColor) === 'undefined' || iconColor === null) {
					iconColor = 'red';
				}
				if (!gicons[iconColor]) {
					gicons[iconColor] = new google.maps.MarkerImage('//maps.google.com/mapfiles/marker'+ iconColor +'.png',
					new google.maps.Size(20, 34),
					new google.maps.Point(0,0),
					new google.maps.Point(9, 34));
				}
				return gicons[iconColor];
			}

			var sv2_bear = null;
			var sv2_elev = null;
			var sv2_zoom = null;
			var placer   = null;

			// A function to create the marker and set up the event window
			function createMarker(latlng, html, tooltip, sv_lati, sv_long, sv_bearing, sv_elevation, sv_zoom, sv_point, marker_icon) {
				var contentString = '<div id="iwcontent">'+html+'</div>';

				// Use flag icon (if defined) instead of regular marker icon
				if (marker_icon) {
					var icon_image = new google.maps.MarkerImage(WT_STATIC_URL+WT_MODULES_DIR+'googlemap/'+marker_icon,
						new google.maps.Size(25, 15),
						new google.maps.Point(0,0),
						new google.maps.Point(12, 15));
					var icon_shadow = new google.maps.MarkerImage(WT_STATIC_URL+WT_MODULES_DIR+'googlemap/images/flag_shadow.png',
						new google.maps.Size(35, 45), // Shadow size
						new google.maps.Point(0,0),   // Shadow origin
						new google.maps.Point(1, 45)  // Shadow anchor is base of flagpole
					);
				} else {
					var icon_image = getMarkerImage('red');
					var icon_shadow = iconShadow;
				}

				// Decide if marker point is Regular (latlng) or StreetView (sv_point) derived
				if (sv_point == '(0, 0)' || sv_point == '(null, null)') {
					placer = latlng;
				} else {
					placer = sv_point;
				}

				// Define the marker
				var marker = new google.maps.Marker({
					position: placer,
					icon:     icon_image,
					shadow:   icon_shadow,
					map:      map,
					title:    tooltip,
					zIndex:   Math.round(latlng.lat()*-100000)<<5
				});

				// Store the tab and event info as marker properties
				marker.sv_lati  = sv_lati;
				marker.sv_long  = sv_long;
				marker.sv_point = sv_point;

				if (sv_bearing == '') {
					marker.sv_bearing = 0;
				} else {
					marker.sv_bearing = sv_bearing;
				}
				if (sv_elevation == '') {
					marker.sv_elevation = 5;
				} else {
					marker.sv_elevation = sv_elevation;
				}
				if (sv_zoom == '' || sv_zoom == 0 || sv_zoom == 1) {
					marker.sv_zoom = 1.2;
				} else {
					marker.sv_zoom = sv_zoom;
				}

				marker.sv_latlng = new google.maps.LatLng(sv_lati, sv_long);
				gmarkers.push(marker);

				// Open infowindow when marker is clicked
				google.maps.event.addListener(marker, 'click', function() {
					infowindow.close();
					infowindow.setContent(contentString);
					infowindow.open(map, marker);
					var panoramaOptions = {
						position:          marker.position,
						mode:              'html5',
						navigationControl: false,
						linksControl:      false,
						addressControl:    false,
						pov: {
							heading: sv_bearing,
							pitch:   sv_elevation,
							zoom:    sv_zoom
						}
					};

					// Use jquery for info window tabs
					google.maps.event.addListener(infowindow, 'domready', function() {
						//jQuery code here
						jQuery('#EV').click(function() {
							document.tabLayerEV = document.getElementById("EV");
							document.tabLayerEV.style.background = '#ffffff';
							document.tabLayerEV.style.paddingBottom = '1px';
							<?php 
        if ($STREETVIEW) {
            ?>
							document.tabLayerSV = document.getElementById("SV");
							document.tabLayerSV.style.background = '#cccccc';
							document.tabLayerSV.style.paddingBottom = '0px';
							<?php 
        }
        ?>
							document.panelLayer1 = document.getElementById("pane1");
							document.panelLayer1.style.display = 'block';
							<?php 
        if ($STREETVIEW) {
            ?>
							document.panelLayer2 = document.getElementById("pane2");
							document.panelLayer2.style.display = 'none';
							<?php 
        }
        ?>
						});

						jQuery('#SV').click(function() {
							document.tabLayerEV = document.getElementById("EV");
							document.tabLayerEV.style.background = '#cccccc';
							document.tabLayerEV.style.paddingBottom = '0px';
							<?php 
        if ($STREETVIEW) {
            ?>
							document.tabLayerSV = document.getElementById("SV");
							document.tabLayerSV.style.background = '#ffffff';
							document.tabLayerSV.style.paddingBottom = '1px';
							<?php 
        }
        ?>
							document.panelLayer1 = document.getElementById("pane1");
							document.panelLayer1.style.display = 'none';
							<?php 
        if ($STREETVIEW) {
            ?>
							document.panelLayer2 = document.getElementById("pane2");
							document.panelLayer2.style.display = 'block';
							<?php 
        }
        ?>
							var panorama = new google.maps.StreetViewPanorama(document.getElementById("pano"), panoramaOptions);
							setTimeout(function() { panorama.setVisible(true); }, 100);
							setTimeout(function() { panorama.setVisible(true); }, 500);
						});
					});
				});
			}

			// Opens Marker infowindow when corresponding Sidebar item is clicked
			function myclick(i) {
				infowindow.close();
				google.maps.event.trigger(gmarkers[i], 'click');
				return false;
			}

			// Home control
			// returns the user to the original map position ... loadMap() function
			// This constructor takes the control DIV as an argument.
			function HomeControl(controlDiv, map) {
				// Set CSS styles for the DIV containing the control
				// Setting padding to 5 px will offset the control from the edge of the map
				controlDiv.style.paddingTop = '5px';
				controlDiv.style.paddingRight = '0px';

				// Set CSS for the control border
				var controlUI = document.createElement('DIV');
				controlUI.style.backgroundColor = 'white';
				controlUI.style.borderStyle = 'solid';
				controlUI.style.borderWidth = '2px';
				controlUI.style.cursor = 'pointer';
				controlUI.style.textAlign = 'center';
				controlUI.title = '';
				controlDiv.appendChild(controlUI);

				// Set CSS for the control interior
				var controlText = document.createElement('DIV');
				controlText.style.fontFamily = 'Arial,sans-serif';
				controlText.style.fontSize = '12px';
				controlText.style.paddingLeft = '15px';
				controlText.style.paddingRight = '15px';
				controlText.innerHTML = '<b><?php 
        echo I18N::translate('Redraw map');
        ?>
</b>';
				controlUI.appendChild(controlText);

				// Setup the click event listeners: simply set the map to original LatLng
				google.maps.event.addDomListener(controlUI, 'click', function() {
					loadMap();
				});
			}

			function loadMap() {
				// Create the map and mapOptions
				var mapOptions = {
					zoom: 7,
					center: map_center,
					mapTypeId: google.maps.MapTypeId.<?php 
        echo $this->getSetting('GM_MAP_TYPE');
        ?>
,
					mapTypeControlOptions: {
						style: google.maps.MapTypeControlStyle.DROPDOWN_MENU  // DEFAULT, DROPDOWN_MENU, HORIZONTAL_BAR
					},
					navigationControl: true,
					navigationControlOptions: {
					position: google.maps.ControlPosition.TOP_RIGHT,  // BOTTOM, BOTTOM_LEFT, LEFT, TOP, etc
					style: google.maps.NavigationControlStyle.SMALL  // ANDROID, DEFAULT, SMALL, ZOOM_PAN
					},
					streetViewControl: false,  // Show Pegman or not
					scrollwheel: false
				};
				map = new google.maps.Map(document.getElementById('map_pane'), mapOptions);

				// Close any infowindow when map is clicked
				google.maps.event.addListener(map, 'click', function() {
					infowindow.close();
				});

				// Create the Home DIV and call the HomeControl() constructor in this DIV.
				var homeControlDiv = document.createElement('DIV');
				var homeControl = new HomeControl(homeControlDiv, map);
				homeControlDiv.index = 1;
				map.controls[google.maps.ControlPosition.TOP_RIGHT].push(homeControlDiv);

				// Add the markers to the map from the $gmarks array
				var locations = [
					<?php 
        foreach ($gmarks as $n => $gmark) {
            ?>
					<?php 
            echo $n ? ',' : '';
            ?>
					{
						"event":        "<?php 
            echo Filter::escapeJs($gmark['fact_label']);
            ?>
",
						"lat":          "<?php 
            echo Filter::escapeJs($gmark['lat']);
            ?>
",
						"lng":          "<?php 
            echo Filter::escapeJs($gmark['lng']);
            ?>
",
						"date":         "<?php 
            echo Filter::escapeJs($gmark['date']);
            ?>
",
						"info":         "<?php 
            echo Filter::escapeJs($gmark['info']);
            ?>
",
						"name":         "<?php 
            echo Filter::escapeJs($gmark['name']);
            ?>
",
						"place":        "<?php 
            echo Filter::escapeJs($gmark['place']);
            ?>
",
						"tooltip":      "<?php 
            echo Filter::escapeJs($gmark['tooltip']);
            ?>
",
						"image":        "<?php 
            echo Filter::escapeJs($gmark['image']);
            ?>
",
						"pl_icon":      "<?php 
            echo Filter::escapeJs($gmark['pl_icon']);
            ?>
",
						"sv_lati":      "<?php 
            echo Filter::escapeJs($gmark['sv_lati']);
            ?>
",
						"sv_long":      "<?php 
            echo Filter::escapeJs($gmark['sv_long']);
            ?>
",
						"sv_bearing":   "<?php 
            echo Filter::escapeJs($gmark['sv_bearing']);
            ?>
",
						"sv_elevation": "<?php 
            echo Filter::escapeJs($gmark['sv_elevation']);
            ?>
",
						"sv_zoom":      "<?php 
            echo Filter::escapeJs($gmark['sv_zoom']);
            ?>
"
					}
					<?php 
        }
        ?>
				];

				// Group the markers by location
				var location_groups = [];
				for (var key in locations) {
					if (!location_groups.hasOwnProperty(locations[key].place)) {
						location_groups[locations[key].place] = [];
					}
					location_groups[locations[key].place].push(locations[key]);
				}

				// Set the Marker bounds
				var bounds = new google.maps.LatLngBounds ();

				var key;
				// Iterate over each location
				for (key in location_groups) {
					var locations = location_groups[key];
					// Iterate over each marker at this location
					var event_details = '';
					for (var j in locations) {
						var location = locations[j];
						if (location.info && location.name) {
							event_details += '<table><tr><td class="highlt_img">' + location.image + '</td><td><p><span id="sp1">' + location.event + '</span> ' + location.info + '<br><b>' + location.name + '</b><br>' + location.date + '<br></p></td></tr></table>';
						} else if (location.name) {
							event_details += '<table><tr><td class="highlt_img">' + location.image + '</td><td><p><span id="sp1">' + location.event + '</span><br><b>' + location.name + '</b><br>' + location.date + '<br></p></td></tr></table>';
						} else if (location.info) {
							event_details += '<table><tr><td class="highlt_img">' + location.image + '</td><td><p><span id="sp1">' + location.event + '</span> ' + location.info + '<br>' + location.date + '<br></p></td></tr></table>';
						} else {
							event_details += '<table><tr><td class="highlt_img">' + location.image + '</td><td><p><span id="sp1">' + location.event + '</span><br>' + location.date + '<br></p></td></tr></table>';
						}
					}
					// All locations are the same in each group, so create a marker with the first
					var location = location_groups[key][0];
					var html =
					'<div class="infowindow">' +
						'<div id="gmtabs">' +
							'<ul class="tabs" >' +
								'<li><a href="#event" id="EV"><?php 
        echo I18N::translate('Events');
        ?>
</a></li>' +
								<?php 
        if ($STREETVIEW) {
            ?>
								'<li><a href="#sview" id="SV"><?php 
            echo I18N::translate('Google Street View™');
            ?>
</a></li>' +
								<?php 
        }
        ?>
							'</ul>' +
							'<div class="panes">' +
								'<div id="pane1">' +
									'<h4 id="iwhead">' + location.place + '</h4>' +
									event_details +
								'</div>' +
								<?php 
        if ($STREETVIEW) {
            ?>
								'<div id="pane2">' +
									'<h4 id="iwhead">' + location.place + '</h4>' +
									'<div id="pano"></div>' +
								'</div>' +
								<?php 
        }
        ?>
							'</div>' +
						'</div>' +
					'</div>';

					// create the marker
					var point        = new google.maps.LatLng(location.lat,     location.lng);     // Place Latitude, Longitude
					var sv_point     = new google.maps.LatLng(location.sv_lati, location.sv_long); // StreetView Latitude and Longitide

					var zoomLevel = <?php 
        echo $GM_MAX_ZOOM;
        ?>
;
					var marker    = createMarker(point, html, location.tooltip, location.sv_lati, location.sv_long, location.sv_bearing, location.sv_elevation, location.sv_zoom, sv_point, location.pl_icon);

					// if streetview coordinates are available, use them for marker,
					// else use the place coordinates
					if (sv_point && sv_point != "(0, 0)") {
						var myLatLng = sv_point;
					} else {
						var myLatLng = point;
					}

					// Correct zoom level when only one marker is present
					if (location_groups.length == 1) {
						bounds.extend(myLatLng);
						map.setZoom(zoomLevel);
						map.setCenter(myLatLng);
					} else {
						bounds.extend(myLatLng);
						map.fitBounds(bounds);
						// Correct zoom level when multiple markers have the same coordinates
						var listener1 = google.maps.event.addListenerOnce(map, "idle", function() {
							if (map.getZoom() > zoomLevel) {
								map.setZoom(zoomLevel);
							}
							google.maps.event.removeListener(listener1);
						});
					}
				} // end loop through location markers
			} // end loadMap()

		</script>
		<?php 
        // Create the normal googlemap sidebar of events and children
        echo '<div style="overflow: auto; overflow-x: hidden; overflow-y: auto; height:', $this->getSetting('GM_YSIZE'), 'px;"><table class="facts_table">';
        foreach ($gmarks as $key => $gmark) {
            echo '<tr>';
            echo '<td class="facts_label">';
            echo '<a href="#" onclick="return myclick(\'', Filter::escapeHtml($key), '\')">', $gmark['fact_label'], '</a></td>';
            echo '<td class="', $gmark['class'], '" style="white-space: normal">';
            if ($gmark['info']) {
                echo '<span class="field">', Filter::escapeHtml($gmark['info']), '</span><br>';
            }
            if ($gmark['name']) {
                echo $gmark['name'], '<br>';
            }
            echo $gmark['place'], '<br>';
            if ($gmark['date']) {
                echo $gmark['date'], '<br>';
            }
            echo '</td>';
            echo '</tr>';
        }
        echo '</table></div><br>';
    }
Exemplo n.º 9
0
 /**
  * Convert a relationship path into a relationship name.
  *
  * @param string $path
  * @param Individual $person1
  * @param Individual $person2
  *
  * @return string
  */
 public static function getRelationshipNameFromPath($path, Individual $person1 = null, Individual $person2 = null)
 {
     if (!preg_match('/^(mot|fat|par|hus|wif|spo|son|dau|chi|bro|sis|sib)*$/', $path)) {
         // TODO: Update all the “3 RELA ” values in class_person
         return '<span class="error">' . $path . '</span>';
     }
     // The path does not include the starting person.  In some languages, the
     // translation for a man’s (relative) is different from a woman’s (relative),
     // due to inflection.
     $sex1 = $person1 ? $person1->getSex() : 'U';
     // The sex of the last person in the relationship determines the name in
     // many cases.  e.g. great-aunt / great-uncle
     if (preg_match('/(fat|hus|son|bro)$/', $path)) {
         $sex2 = 'M';
     } elseif (preg_match('/(mot|wif|dau|sis)$/', $path)) {
         $sex2 = 'F';
     } else {
         $sex2 = 'U';
     }
     switch ($path) {
         case '':
             return I18N::translate('self');
             //  Level One relationships
         //  Level One relationships
         case 'mot':
             return I18N::translate('mother');
         case 'fat':
             return I18N::translate('father');
         case 'par':
             return I18N::translate('parent');
         case 'hus':
             if ($person1 && $person2) {
                 foreach ($person1->getSpouseFamilies() as $family) {
                     if ($person2 === $family->getSpouse($person1)) {
                         if ($family->getFacts('_NMR')) {
                             if ($family->getFacts(WT_EVENTS_DIV)) {
                                 return I18N::translateContext('MALE', 'ex-partner');
                             } else {
                                 return I18N::translateContext('MALE', 'partner');
                             }
                         } elseif ($family->getFacts(WT_EVENTS_DIV)) {
                             return I18N::translate('ex-husband');
                         }
                     }
                 }
             }
             return I18N::translate('husband');
         case 'wif':
             if ($person1 && $person1) {
                 foreach ($person1->getSpouseFamilies() as $family) {
                     if ($person2 === $family->getSpouse($person1)) {
                         if ($family->getFacts('_NMR')) {
                             if ($family->getFacts(WT_EVENTS_DIV)) {
                                 return I18N::translateContext('FEMALE', 'ex-partner');
                             } else {
                                 return I18N::translateContext('FEMALE', 'partner');
                             }
                         } elseif ($family->getFacts(WT_EVENTS_DIV)) {
                             return I18N::translate('ex-wife');
                         }
                     }
                 }
             }
             return I18N::translate('wife');
         case 'spo':
             if ($person1 && $person2) {
                 foreach ($person1->getSpouseFamilies() as $family) {
                     if ($person2 === $family->getSpouse($person1)) {
                         if ($family->getFacts('_NMR')) {
                             if ($family->getFacts(WT_EVENTS_DIV)) {
                                 return I18N::translateContext('MALE/FEMALE', 'ex-partner');
                             } else {
                                 return I18N::translateContext('MALE/FEMALE', 'partner');
                             }
                         } elseif ($family->getFacts(WT_EVENTS_DIV)) {
                             return I18N::translate('ex-spouse');
                         }
                     }
                 }
             }
             return I18N::translate('spouse');
         case 'son':
             return I18N::translate('son');
         case 'dau':
             return I18N::translate('daughter');
         case 'chi':
             return I18N::translate('child');
         case 'bro':
             if ($person1 && $person2) {
                 $dob1 = $person1->getBirthDate();
                 $dob2 = $person2->getBirthDate();
                 if ($dob1->isOK() && $dob2->isOK()) {
                     if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && !$dob1->minimumDate()->d !== 0 && !$dob2->minimumDate()->d !== 0) {
                         // Exclude BEF, AFT, etc.
                         return I18N::translate('twin brother');
                     } elseif ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) {
                         return I18N::translate('younger brother');
                     } elseif ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) {
                         return I18N::translate('elder brother');
                     }
                 }
             }
             return I18N::translate('brother');
         case 'sis':
             if ($person1 && $person2) {
                 $dob1 = $person1->getBirthDate();
                 $dob2 = $person2->getBirthDate();
                 if ($dob1->isOK() && $dob2->isOK()) {
                     if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && !$dob1->minimumDate()->d !== 0 && !$dob2->minimumDate()->d !== 0) {
                         // Exclude BEF, AFT, etc.
                         return I18N::translate('twin sister');
                     } elseif ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) {
                         return I18N::translate('younger sister');
                     } elseif ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) {
                         return I18N::translate('elder sister');
                     }
                 }
             }
             return I18N::translate('sister');
         case 'sib':
             if ($person1 && $person2) {
                 $dob1 = $person1->getBirthDate();
                 $dob2 = $person2->getBirthDate();
                 if ($dob1->isOK() && $dob2->isOK()) {
                     if (abs($dob1->julianDay() - $dob2->julianDay()) < 2 && !$dob1->minimumDate()->d !== 0 && !$dob2->minimumDate()->d !== 0) {
                         // Exclude BEF, AFT, etc.
                         return I18N::translate('twin sibling');
                     } elseif ($dob1->maximumJulianDay() < $dob2->minimumJulianDay()) {
                         return I18N::translate('younger sibling');
                     } elseif ($dob1->minimumJulianDay() > $dob2->maximumJulianDay()) {
                         return I18N::translate('elder sibling');
                     }
                 }
             }
             return I18N::translate('sibling');
             // Level Two relationships
         // Level Two relationships
         case 'brochi':
             return I18N::translateContext('brother’s child', 'nephew/niece');
         case 'brodau':
             return I18N::translateContext('brother’s daughter', 'niece');
         case 'broson':
             return I18N::translateContext('brother’s son', 'nephew');
         case 'browif':
             return I18N::translateContext('brother’s wife', 'sister-in-law');
         case 'chichi':
             return I18N::translateContext('child’s child', 'grandchild');
         case 'chidau':
             return I18N::translateContext('child’s daughter', 'granddaughter');
         case 'chihus':
             return I18N::translateContext('child’s husband', 'son-in-law');
         case 'chison':
             return I18N::translateContext('child’s son', 'grandson');
         case 'chispo':
             return I18N::translateContext('child’s spouse', 'son/daughter-in-law');
         case 'chiwif':
             return I18N::translateContext('child’s wife', 'daughter-in-law');
         case 'dauchi':
             return I18N::translateContext('daughter’s child', 'grandchild');
         case 'daudau':
             return I18N::translateContext('daughter’s daughter', 'granddaughter');
         case 'dauhus':
             return I18N::translateContext('daughter’s husband', 'son-in-law');
         case 'dauson':
             return I18N::translateContext('daughter’s son', 'grandson');
         case 'fatbro':
             return I18N::translateContext('father’s brother', 'uncle');
         case 'fatchi':
             return I18N::translateContext('father’s child', 'half-sibling');
         case 'fatdau':
             return I18N::translateContext('father’s daughter', 'half-sister');
         case 'fatfat':
             return I18N::translateContext('father’s father', 'paternal grandfather');
         case 'fatmot':
             return I18N::translateContext('father’s mother', 'paternal grandmother');
         case 'fatpar':
             return I18N::translateContext('father’s parent', 'paternal grandparent');
         case 'fatsib':
             return I18N::translateContext('father’s sibling', 'aunt/uncle');
         case 'fatsis':
             return I18N::translateContext('father’s sister', 'aunt');
         case 'fatson':
             return I18N::translateContext('father’s son', 'half-brother');
         case 'fatwif':
             return I18N::translateContext('father’s wife', 'step-mother');
         case 'husbro':
             return I18N::translateContext('husband’s brother', 'brother-in-law');
         case 'huschi':
             return I18N::translateContext('husband’s child', 'step-child');
         case 'husdau':
             return I18N::translateContext('husband’s daughter', 'step-daughter');
         case 'husfat':
             return I18N::translateContext('husband’s father', 'father-in-law');
         case 'husmot':
             return I18N::translateContext('husband’s mother', 'mother-in-law');
         case 'hussib':
             return I18N::translateContext('husband’s sibling', 'brother/sister-in-law');
         case 'hussis':
             return I18N::translateContext('husband’s sister', 'sister-in-law');
         case 'husson':
             return I18N::translateContext('husband’s son', 'step-son');
         case 'motbro':
             return I18N::translateContext('mother’s brother', 'uncle');
         case 'motchi':
             return I18N::translateContext('mother’s child', 'half-sibling');
         case 'motdau':
             return I18N::translateContext('mother’s daughter', 'half-sister');
         case 'motfat':
             return I18N::translateContext('mother’s father', 'maternal grandfather');
         case 'mothus':
             return I18N::translateContext('mother’s husband', 'step-father');
         case 'motmot':
             return I18N::translateContext('mother’s mother', 'maternal grandmother');
         case 'motpar':
             return I18N::translateContext('mother’s parent', 'maternal grandparent');
         case 'motsib':
             return I18N::translateContext('mother’s sibling', 'aunt/uncle');
         case 'motsis':
             return I18N::translateContext('mother’s sister', 'aunt');
         case 'motson':
             return I18N::translateContext('mother’s son', 'half-brother');
         case 'parbro':
             return I18N::translateContext('parent’s brother', 'uncle');
         case 'parchi':
             return I18N::translateContext('parent’s child', 'half-sibling');
         case 'pardau':
             return I18N::translateContext('parent’s daughter', 'half-sister');
         case 'parfat':
             return I18N::translateContext('parent’s father', 'grandfather');
         case 'parmot':
             return I18N::translateContext('parent’s mother', 'grandmother');
         case 'parpar':
             return I18N::translateContext('parent’s parent', 'grandparent');
         case 'parsib':
             return I18N::translateContext('parent’s sibling', 'aunt/uncle');
         case 'parsis':
             return I18N::translateContext('parent’s sister', 'aunt');
         case 'parson':
             return I18N::translateContext('parent’s son', 'half-brother');
         case 'parspo':
             return I18N::translateContext('parent’s spouse', 'step-parent');
         case 'sibchi':
             return I18N::translateContext('sibling’s child', 'nephew/niece');
         case 'sibdau':
             return I18N::translateContext('sibling’s daughter', 'niece');
         case 'sibson':
             return I18N::translateContext('sibling’s son', 'nephew');
         case 'sibspo':
             return I18N::translateContext('sibling’s spouse', 'brother/sister-in-law');
         case 'sischi':
             return I18N::translateContext('sister’s child', 'nephew/niece');
         case 'sisdau':
             return I18N::translateContext('sister’s daughter', 'niece');
         case 'sishus':
             return I18N::translateContext('sister’s husband', 'brother-in-law');
         case 'sisson':
             return I18N::translateContext('sister’s son', 'nephew');
         case 'sonchi':
             return I18N::translateContext('son’s child', 'grandchild');
         case 'sondau':
             return I18N::translateContext('son’s daughter', 'granddaughter');
         case 'sonson':
             return I18N::translateContext('son’s son', 'grandson');
         case 'sonwif':
             return I18N::translateContext('son’s wife', 'daughter-in-law');
         case 'spobro':
             return I18N::translateContext('spouse’s brother', 'brother-in-law');
         case 'spochi':
             return I18N::translateContext('spouse’s child', 'step-child');
         case 'spodau':
             return I18N::translateContext('spouse’s daughter', 'step-daughter');
         case 'spofat':
             return I18N::translateContext('spouse’s father', 'father-in-law');
         case 'spomot':
             return I18N::translateContext('spouse’s mother', 'mother-in-law');
         case 'sposis':
             return I18N::translateContext('spouse’s sister', 'sister-in-law');
         case 'sposon':
             return I18N::translateContext('spouse’s son', 'step-son');
         case 'spopar':
             return I18N::translateContext('spouse’s parent', 'mother/father-in-law');
         case 'sposib':
             return I18N::translateContext('spouse’s sibling', 'brother/sister-in-law');
         case 'wifbro':
             return I18N::translateContext('wife’s brother', 'brother-in-law');
         case 'wifchi':
             return I18N::translateContext('wife’s child', 'step-child');
         case 'wifdau':
             return I18N::translateContext('wife’s daughter', 'step-daughter');
         case 'wiffat':
             return I18N::translateContext('wife’s father', 'father-in-law');
         case 'wifmot':
             return I18N::translateContext('wife’s mother', 'mother-in-law');
         case 'wifsib':
             return I18N::translateContext('wife’s sibling', 'brother/sister-in-law');
         case 'wifsis':
             return I18N::translateContext('wife’s sister', 'sister-in-law');
         case 'wifson':
             return I18N::translateContext('wife’s son', 'step-son');
             // Level Three relationships
             // I have commented out some of the unknown-sex relationships that are unlikely to to occur.
             // Feel free to add them in, if you think they might be needed
         // Level Three relationships
         // I have commented out some of the unknown-sex relationships that are unlikely to to occur.
         // Feel free to add them in, if you think they might be needed
         case 'brochichi':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s child’s child', 'great-nephew/niece');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s child’s child', 'great-nephew/niece');
             }
         case 'brochidau':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s child’s daughter', 'great-niece');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s child’s daughter', 'great-niece');
             }
         case 'brochison':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s child’s son', 'great-nephew');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s child’s son', 'great-nephew');
             }
         case 'brodauchi':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s daughter’s child', 'great-nephew/niece');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s daughter’s child', 'great-nephew/niece');
             }
         case 'brodaudau':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s daughter’s daughter', 'great-niece');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s daughter’s daughter', 'great-niece');
             }
         case 'brodauhus':
             return I18N::translateContext('brother’s daughter’s husband', 'nephew-in-law');
         case 'brodauson':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s daughter’s son', 'great-nephew');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s daughter’s son', 'great-nephew');
             }
         case 'brosonchi':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s son’s child', 'great-nephew/niece');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s son’s child', 'great-nephew/niece');
             }
         case 'brosondau':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s son’s daughter', 'great-niece');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s son’s daughter', 'great-niece');
             }
         case 'brosonson':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) brother’s son’s son', 'great-nephew');
             } else {
                 return I18N::translateContext('(a woman’s) brother’s son’s son', 'great-nephew');
             }
         case 'brosonwif':
             return I18N::translateContext('brother’s son’s wife', 'niece-in-law');
         case 'browifbro':
             return I18N::translateContext('brother’s wife’s brother', 'brother-in-law');
         case 'browifsib':
             return I18N::translateContext('brother’s wife’s sibling', 'brother/sister-in-law');
         case 'browifsis':
             return I18N::translateContext('brother’s wife’s sister', 'sister-in-law');
         case 'chichichi':
             return I18N::translateContext('child’s child’s child', 'great-grandchild');
         case 'chichidau':
             return I18N::translateContext('child’s child’s daughter', 'great-granddaughter');
         case 'chichison':
             return I18N::translateContext('child’s child’s son', 'great-grandson');
         case 'chidauchi':
             return I18N::translateContext('child’s daughter’s child', 'great-grandchild');
         case 'chidaudau':
             return I18N::translateContext('child’s daughter’s daughter', 'great-granddaughter');
         case 'chidauhus':
             return I18N::translateContext('child’s daughter’s husband', 'granddaughter’s husband');
         case 'chidauson':
             return I18N::translateContext('child’s daughter’s son', 'great-grandson');
         case 'chisonchi':
             return I18N::translateContext('child’s son’s child', 'great-grandchild');
         case 'chisondau':
             return I18N::translateContext('child’s son’s daughter', 'great-granddaughter');
         case 'chisonson':
             return I18N::translateContext('child’s son’s son', 'great-grandson');
         case 'chisonwif':
             return I18N::translateContext('child’s son’s wife', 'grandson’s wife');
         case 'dauchichi':
             return I18N::translateContext('daughter’s child’s child', 'great-grandchild');
         case 'dauchidau':
             return I18N::translateContext('daughter’s child’s daughter', 'great-granddaughter');
         case 'dauchison':
             return I18N::translateContext('daughter’s child’s son', 'great-grandson');
         case 'daudauchi':
             return I18N::translateContext('daughter’s daughter’s child', 'great-grandchild');
         case 'daudaudau':
             return I18N::translateContext('daughter’s daughter’s daughter', 'great-granddaughter');
         case 'daudauhus':
             return I18N::translateContext('daughter’s daughter’s husband', 'granddaughter’s husband');
         case 'daudauson':
             return I18N::translateContext('daughter’s daughter’s son', 'great-grandson');
         case 'dauhusfat':
             return I18N::translateContext('daughter’s husband’s father', 'son-in-law’s father');
         case 'dauhusmot':
             return I18N::translateContext('daughter’s husband’s mother', 'son-in-law’s mother');
         case 'dauhuspar':
             return I18N::translateContext('daughter’s husband’s parent', 'son-in-law’s parent');
         case 'dausonchi':
             return I18N::translateContext('daughter’s son’s child', 'great-grandchild');
         case 'dausondau':
             return I18N::translateContext('daughter’s son’s daughter', 'great-granddaughter');
         case 'dausonson':
             return I18N::translateContext('daughter’s son’s son', 'great-grandson');
         case 'dausonwif':
             return I18N::translateContext('daughter’s son’s wife', 'grandson’s wife');
         case 'fatbrochi':
             return I18N::translateContext('father’s brother’s child', 'first cousin');
         case 'fatbrodau':
             return I18N::translateContext('father’s brother’s daughter', 'first cousin');
         case 'fatbroson':
             return I18N::translateContext('father’s brother’s son', 'first cousin');
         case 'fatbrowif':
             return I18N::translateContext('father’s brother’s wife', 'aunt');
         case 'fatfatbro':
             return I18N::translateContext('father’s father’s brother', 'great-uncle');
         case 'fatfatfat':
             return I18N::translateContext('father’s father’s father', 'great-grandfather');
         case 'fatfatmot':
             return I18N::translateContext('father’s father’s mother', 'great-grandmother');
         case 'fatfatpar':
             return I18N::translateContext('father’s father’s parent', 'great-grandparent');
         case 'fatfatsib':
             return I18N::translateContext('father’s father’s sibling', 'great-aunt/uncle');
         case 'fatfatsis':
             return I18N::translateContext('father’s father’s sister', 'great-aunt');
         case 'fatmotbro':
             return I18N::translateContext('father’s mother’s brother', 'great-uncle');
         case 'fatmotfat':
             return I18N::translateContext('father’s mother’s father', 'great-grandfather');
         case 'fatmotmot':
             return I18N::translateContext('father’s mother’s mother', 'great-grandmother');
         case 'fatmotpar':
             return I18N::translateContext('father’s mother’s parent', 'great-grandparent');
         case 'fatmotsib':
             return I18N::translateContext('father’s mother’s sibling', 'great-aunt/uncle');
         case 'fatmotsis':
             return I18N::translateContext('father’s mother’s sister', 'great-aunt');
         case 'fatparbro':
             return I18N::translateContext('father’s parent’s brother', 'great-uncle');
         case 'fatparfat':
             return I18N::translateContext('father’s parent’s father', 'great-grandfather');
         case 'fatparmot':
             return I18N::translateContext('father’s parent’s mother', 'great-grandmother');
         case 'fatparpar':
             return I18N::translateContext('father’s parent’s parent', 'great-grandparent');
         case 'fatparsib':
             return I18N::translateContext('father’s parent’s sibling', 'great-aunt/uncle');
         case 'fatparsis':
             return I18N::translateContext('father’s parent’s sister', 'great-aunt');
         case 'fatsischi':
             return I18N::translateContext('father’s sister’s child', 'first cousin');
         case 'fatsisdau':
             return I18N::translateContext('father’s sister’s daughter', 'first cousin');
         case 'fatsishus':
             return I18N::translateContext('father’s sister’s husband', 'uncle');
         case 'fatsisson':
             return I18N::translateContext('father’s sister’s son', 'first cousin');
         case 'fatwifchi':
             return I18N::translateContext('father’s wife’s child', 'step-sibling');
         case 'fatwifdau':
             return I18N::translateContext('father’s wife’s daughter', 'step-sister');
         case 'fatwifson':
             return I18N::translateContext('father’s wife’s son', 'step-brother');
         case 'husbrowif':
             return I18N::translateContext('husband’s brother’s wife', 'sister-in-law');
         case 'hussishus':
             return I18N::translateContext('husband’s sister’s husband', 'brother-in-law');
         case 'motbrochi':
             return I18N::translateContext('mother’s brother’s child', 'first cousin');
         case 'motbrodau':
             return I18N::translateContext('mother’s brother’s daughter', 'first cousin');
         case 'motbroson':
             return I18N::translateContext('mother’s brother’s son', 'first cousin');
         case 'motbrowif':
             return I18N::translateContext('mother’s brother’s wife', 'aunt');
         case 'motfatbro':
             return I18N::translateContext('mother’s father’s brother', 'great-uncle');
         case 'motfatfat':
             return I18N::translateContext('mother’s father’s father', 'great-grandfather');
         case 'motfatmot':
             return I18N::translateContext('mother’s father’s mother', 'great-grandmother');
         case 'motfatpar':
             return I18N::translateContext('mother’s father’s parent', 'great-grandparent');
         case 'motfatsib':
             return I18N::translateContext('mother’s father’s sibling', 'great-aunt/uncle');
         case 'motfatsis':
             return I18N::translateContext('mother’s father’s sister', 'great-aunt');
         case 'mothuschi':
             return I18N::translateContext('mother’s husband’s child', 'step-sibling');
         case 'mothusdau':
             return I18N::translateContext('mother’s husband’s daughter', 'step-sister');
         case 'mothusson':
             return I18N::translateContext('mother’s husband’s son', 'step-brother');
         case 'motmotbro':
             return I18N::translateContext('mother’s mother’s brother', 'great-uncle');
         case 'motmotfat':
             return I18N::translateContext('mother’s mother’s father', 'great-grandfather');
         case 'motmotmot':
             return I18N::translateContext('mother’s mother’s mother', 'great-grandmother');
         case 'motmotpar':
             return I18N::translateContext('mother’s mother’s parent', 'great-grandparent');
         case 'motmotsib':
             return I18N::translateContext('mother’s mother’s sibling', 'great-aunt/uncle');
         case 'motmotsis':
             return I18N::translateContext('mother’s mother’s sister', 'great-aunt');
         case 'motparbro':
             return I18N::translateContext('mother’s parent’s brother', 'great-uncle');
         case 'motparfat':
             return I18N::translateContext('mother’s parent’s father', 'great-grandfather');
         case 'motparmot':
             return I18N::translateContext('mother’s parent’s mother', 'great-grandmother');
         case 'motparpar':
             return I18N::translateContext('mother’s parent’s parent', 'great-grandparent');
         case 'motparsib':
             return I18N::translateContext('mother’s parent’s sibling', 'great-aunt/uncle');
         case 'motparsis':
             return I18N::translateContext('mother’s parent’s sister', 'great-aunt');
         case 'motsischi':
             return I18N::translateContext('mother’s sister’s child', 'first cousin');
         case 'motsisdau':
             return I18N::translateContext('mother’s sister’s daughter', 'first cousin');
         case 'motsishus':
             return I18N::translateContext('mother’s sister’s husband', 'uncle');
         case 'motsisson':
             return I18N::translateContext('mother’s sister’s son', 'first cousin');
         case 'parbrowif':
             return I18N::translateContext('parent’s brother’s wife', 'aunt');
         case 'parfatbro':
             return I18N::translateContext('parent’s father’s brother', 'great-uncle');
         case 'parfatfat':
             return I18N::translateContext('parent’s father’s father', 'great-grandfather');
         case 'parfatmot':
             return I18N::translateContext('parent’s father’s mother', 'great-grandmother');
         case 'parfatpar':
             return I18N::translateContext('parent’s father’s parent', 'great-grandparent');
         case 'parfatsib':
             return I18N::translateContext('parent’s father’s sibling', 'great-aunt/uncle');
         case 'parfatsis':
             return I18N::translateContext('parent’s father’s sister', 'great-aunt');
         case 'parmotbro':
             return I18N::translateContext('parent’s mother’s brother', 'great-uncle');
         case 'parmotfat':
             return I18N::translateContext('parent’s mother’s father', 'great-grandfather');
         case 'parmotmot':
             return I18N::translateContext('parent’s mother’s mother', 'great-grandmother');
         case 'parmotpar':
             return I18N::translateContext('parent’s mother’s parent', 'great-grandparent');
         case 'parmotsib':
             return I18N::translateContext('parent’s mother’s sibling', 'great-aunt/uncle');
         case 'parmotsis':
             return I18N::translateContext('parent’s mother’s sister', 'great-aunt');
         case 'parparbro':
             return I18N::translateContext('parent’s parent’s brother', 'great-uncle');
         case 'parparfat':
             return I18N::translateContext('parent’s parent’s father', 'great-grandfather');
         case 'parparmot':
             return I18N::translateContext('parent’s parent’s mother', 'great-grandmother');
         case 'parparpar':
             return I18N::translateContext('parent’s parent’s parent', 'great-grandparent');
         case 'parparsib':
             return I18N::translateContext('parent’s parent’s sibling', 'great-aunt/uncle');
         case 'parparsis':
             return I18N::translateContext('parent’s parent’s sister', 'great-aunt');
         case 'parsishus':
             return I18N::translateContext('parent’s sister’s husband', 'uncle');
         case 'parspochi':
             return I18N::translateContext('parent’s spouse’s child', 'step-sibling');
         case 'parspodau':
             return I18N::translateContext('parent’s spouse’s daughter', 'step-sister');
         case 'parsposon':
             return I18N::translateContext('parent’s spouse’s son', 'step-brother');
         case 'sibchichi':
             return I18N::translateContext('sibling’s child’s child', 'great-nephew/niece');
         case 'sibchidau':
             return I18N::translateContext('sibling’s child’s daughter', 'great-niece');
         case 'sibchison':
             return I18N::translateContext('sibling’s child’s son', 'great-nephew');
         case 'sibdauchi':
             return I18N::translateContext('sibling’s daughter’s child', 'great-nephew/niece');
         case 'sibdaudau':
             return I18N::translateContext('sibling’s daughter’s daughter', 'great-niece');
         case 'sibdauhus':
             return I18N::translateContext('sibling’s daughter’s husband', 'nephew-in-law');
         case 'sibdauson':
             return I18N::translateContext('sibling’s daughter’s son', 'great-nephew');
         case 'sibsonchi':
             return I18N::translateContext('sibling’s son’s child', 'great-nephew/niece');
         case 'sibsondau':
             return I18N::translateContext('sibling’s son’s daughter', 'great-niece');
         case 'sibsonson':
             return I18N::translateContext('sibling’s son’s son', 'great-nephew');
         case 'sibsonwif':
             return I18N::translateContext('sibling’s son’s wife', 'niece-in-law');
         case 'sischichi':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s child’s child', 'great-nephew/niece');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s child’s child', 'great-nephew/niece');
             }
         case 'sischidau':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s child’s daughter', 'great-niece');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s child’s daughter', 'great-niece');
             }
         case 'sischison':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s child’s son', 'great-nephew');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s child’s son', 'great-nephew');
             }
         case 'sisdauchi':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s daughter’s child', 'great-nephew/niece');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s daughter’s child', 'great-nephew/niece');
             }
         case 'sisdaudau':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s daughter’s daughter', 'great-niece');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s daughter’s daughter', 'great-niece');
             }
         case 'sisdauhus':
             return I18N::translateContext('sisters’s daughter’s husband', 'nephew-in-law');
         case 'sisdauson':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s daughter’s son', 'great-nephew');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s daughter’s son', 'great-nephew');
             }
         case 'sishusbro':
             return I18N::translateContext('sister’s husband’s brother', 'brother-in-law');
         case 'sishussib':
             return I18N::translateContext('sister’s husband’s sibling', 'brother/sister-in-law');
         case 'sishussis':
             return I18N::translateContext('sister’s husband’s sister', 'sister-in-law');
         case 'sissonchi':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s son’s child', 'great-nephew/niece');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s son’s child', 'great-nephew/niece');
             }
         case 'sissondau':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s son’s daughter', 'great-niece');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s son’s daughter', 'great-niece');
             }
         case 'sissonson':
             if ($sex1 === 'M') {
                 return I18N::translateContext('(a man’s) sister’s son’s son', 'great-nephew');
             } else {
                 return I18N::translateContext('(a woman’s) sister’s son’s son', 'great-nephew');
             }
         case 'sissonwif':
             return I18N::translateContext('sisters’s son’s wife', 'niece-in-law');
         case 'sonchichi':
             return I18N::translateContext('son’s child’s child', 'great-grandchild');
         case 'sonchidau':
             return I18N::translateContext('son’s child’s daughter', 'great-granddaughter');
         case 'sonchison':
             return I18N::translateContext('son’s child’s son', 'great-grandson');
         case 'sondauchi':
             return I18N::translateContext('son’s daughter’s child', 'great-grandchild');
         case 'sondaudau':
             return I18N::translateContext('son’s daughter’s daughter', 'great-granddaughter');
         case 'sondauhus':
             return I18N::translateContext('son’s daughter’s husband', 'granddaughter’s husband');
         case 'sondauson':
             return I18N::translateContext('son’s daughter’s son', 'great-grandson');
         case 'sonsonchi':
             return I18N::translateContext('son’s son’s child', 'great-grandchild');
         case 'sonsondau':
             return I18N::translateContext('son’s son’s daughter', 'great-granddaughter');
         case 'sonsonson':
             return I18N::translateContext('son’s son’s son', 'great-grandson');
         case 'sonsonwif':
             return I18N::translateContext('son’s son’s wife', 'grandson’s wife');
         case 'sonwiffat':
             return I18N::translateContext('son’s wife’s father', 'daughter-in-law’s father');
         case 'sonwifmot':
             return I18N::translateContext('son’s wife’s mother', 'daughter-in-law’s mother');
         case 'sonwifpar':
             return I18N::translateContext('son’s wife’s parent', 'daughter-in-law’s parent');
         case 'wifbrowif':
             return I18N::translateContext('wife’s brother’s wife', 'sister-in-law');
         case 'wifsishus':
             return I18N::translateContext('wife’s sister’s husband', 'brother-in-law');
             // Some “special case” level four relationships that have specific names in certain languages
         // Some “special case” level four relationships that have specific names in certain languages
         case 'fatfatbrowif':
             return I18N::translateContext('father’s father’s brother’s wife', 'great-aunt');
         case 'fatfatsibspo':
             return I18N::translateContext('father’s father’s sibling’s spouse', 'great-aunt/uncle');
         case 'fatfatsishus':
             return I18N::translateContext('father’s father’s sister’s husband', 'great-uncle');
         case 'fatmotbrowif':
             return I18N::translateContext('father’s mother’s brother’s wife', 'great-aunt');
         case 'fatmotsibspo':
             return I18N::translateContext('father’s mother’s sibling’s spouse', 'great-aunt/uncle');
         case 'fatmotsishus':
             return I18N::translateContext('father’s mother’s sister’s husband', 'great-uncle');
         case 'fatparbrowif':
             return I18N::translateContext('father’s parent’s brother’s wife', 'great-aunt');
         case 'fatparsibspo':
             return I18N::translateContext('father’s parent’s sibling’s spouse', 'great-aunt/uncle');
         case 'fatparsishus':
             return I18N::translateContext('father’s parent’s sister’s husband', 'great-uncle');
         case 'motfatbrowif':
             return I18N::translateContext('mother’s father’s brother’s wife', 'great-aunt');
         case 'motfatsibspo':
             return I18N::translateContext('mother’s father’s sibling’s spouse', 'great-aunt/uncle');
         case 'motfatsishus':
             return I18N::translateContext('mother’s father’s sister’s husband', 'great-uncle');
         case 'motmotbrowif':
             return I18N::translateContext('mother’s mother’s brother’s wife', 'great-aunt');
         case 'motmotsibspo':
             return I18N::translateContext('mother’s mother’s sibling’s spouse', 'great-aunt/uncle');
         case 'motmotsishus':
             return I18N::translateContext('mother’s mother’s sister’s husband', 'great-uncle');
         case 'motparbrowif':
             return I18N::translateContext('mother’s parent’s brother’s wife', 'great-aunt');
         case 'motparsibspo':
             return I18N::translateContext('mother’s parent’s sibling’s spouse', 'great-aunt/uncle');
         case 'motparsishus':
             return I18N::translateContext('mother’s parent’s sister’s husband', 'great-uncle');
         case 'parfatbrowif':
             return I18N::translateContext('parent’s father’s brother’s wife', 'great-aunt');
         case 'parfatsibspo':
             return I18N::translateContext('parent’s father’s sibling’s spouse', 'great-aunt/uncle');
         case 'parfatsishus':
             return I18N::translateContext('parent’s father’s sister’s husband', 'great-uncle');
         case 'parmotbrowif':
             return I18N::translateContext('parent’s mother’s brother’s wife', 'great-aunt');
         case 'parmotsibspo':
             return I18N::translateContext('parent’s mother’s sibling’s spouse', 'great-aunt/uncle');
         case 'parmotsishus':
             return I18N::translateContext('parent’s mother’s sister’s husband', 'great-uncle');
         case 'parparbrowif':
             return I18N::translateContext('parent’s parent’s brother’s wife', 'great-aunt');
         case 'parparsibspo':
             return I18N::translateContext('parent’s parent’s sibling’s spouse', 'great-aunt/uncle');
         case 'parparsishus':
             return I18N::translateContext('parent’s parent’s sister’s husband', 'great-uncle');
         case 'fatfatbrodau':
             return I18N::translateContext('father’s father’s brother’s daughter', 'first cousin once removed ascending');
         case 'fatfatbroson':
             return I18N::translateContext('father’s father’s brother’s son', 'first cousin once removed ascending');
         case 'fatfatbrochi':
             return I18N::translateContext('father’s father’s brother’s child', 'first cousin once removed ascending');
         case 'fatfatsisdau':
             return I18N::translateContext('father’s father’s sister’s daughter', 'first cousin once removed ascending');
         case 'fatfatsisson':
             return I18N::translateContext('father’s father’s sister’s son', 'first cousin once removed ascending');
         case 'fatfatsischi':
             return I18N::translateContext('father’s father’s sister’s child', 'first cousin once removed ascending');
         case 'fatmotbrodau':
             return I18N::translateContext('father’s mother’s brother’s daughter', 'first cousin once removed ascending');
         case 'fatmotbroson':
             return I18N::translateContext('father’s mother’s brother’s son', 'first cousin once removed ascending');
         case 'fatmotbrochi':
             return I18N::translateContext('father’s mother’s brother’s child', 'first cousin once removed ascending');
         case 'fatmotsisdau':
             return I18N::translateContext('father’s mother’s sister’s daughter', 'first cousin once removed ascending');
         case 'fatmotsisson':
             return I18N::translateContext('father’s mother’s sister’s son', 'first cousin once removed ascending');
         case 'fatmotsischi':
             return I18N::translateContext('father’s mother’s sister’s child', 'first cousin once removed ascending');
         case 'motfatbrodau':
             return I18N::translateContext('mother’s father’s brother’s daughter', 'first cousin once removed ascending');
         case 'motfatbroson':
             return I18N::translateContext('mother’s father’s brother’s son', 'first cousin once removed ascending');
         case 'motfatbrochi':
             return I18N::translateContext('mother’s father’s brother’s child', 'first cousin once removed ascending');
         case 'motfatsisdau':
             return I18N::translateContext('mother’s father’s sister’s daughter', 'first cousin once removed ascending');
         case 'motfatsisson':
             return I18N::translateContext('mother’s father’s sister’s son', 'first cousin once removed ascending');
         case 'motfatsischi':
             return I18N::translateContext('mother’s father’s sister’s child', 'first cousin once removed ascending');
         case 'motmotbrodau':
             return I18N::translateContext('mother’s mother’s brother’s daughter', 'first cousin once removed ascending');
         case 'motmotbroson':
             return I18N::translateContext('mother’s mother’s brother’s son', 'first cousin once removed ascending');
         case 'motmotbrochi':
             return I18N::translateContext('mother’s mother’s brother’s child', 'first cousin once removed ascending');
         case 'motmotsisdau':
             return I18N::translateContext('mother’s mother’s sister’s daughter', 'first cousin once removed ascending');
         case 'motmotsisson':
             return I18N::translateContext('mother’s mother’s sister’s son', 'first cousin once removed ascending');
         case 'motmotsischi':
             return I18N::translateContext('mother’s mother’s sister’s child', 'first cousin once removed ascending');
     }
     // Some “special case” level five relationships that have specific names in certain languages
     if (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandfather’s brother’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandfather’s brother’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)fatbro(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandfather’s brother’s grandchild', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandfather’s sister’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandfather’s sister’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)fatsis(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandfather’s sister’s grandchild', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandfather’s sibling’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandfather’s sibling’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)fatsib(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandfather’s sibling’s grandchild', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motbro(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandmother’s brother’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motbro(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandmother’s brother’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motbro(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandmother’s brother’s grandchild', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motsis(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandmother’s sister’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motsis(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandmother’s sister’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motsis(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandmother’s sister’s grandchild', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motsib(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandmother’s sibling’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motsib(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandmother’s sibling’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)motsib(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandmother’s sibling’s grandchild', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parbro(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandparent’s brother’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parbro(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandparent’s brother’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parbro(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandparent’s brother’s grandchild', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parsis(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandparent’s sister’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parsis(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandparent’s sister’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parsis(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandparent’s sister’s grandchild', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parsib(son|dau|chi)dau$/', $path)) {
         return I18N::translateContext('grandparent’s sibling’s granddaughter', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parsib(son|dau|chi)son$/', $path)) {
         return I18N::translateContext('grandparent’s sibling’s grandson', 'second cousin');
     } elseif (preg_match('/^(mot|fat|par)parsib(son|dau|chi)chi$/', $path)) {
         return I18N::translateContext('grandparent’s sibling’s grandchild', 'second cousin');
     }
     // Look for generic/pattern relationships.
     if (preg_match('/^((?:mot|fat|par)+)(bro|sis|sib)$/', $path, $match)) {
         // siblings of direct ancestors
         $up = strlen($match[1]) / 3;
         $bef_last = substr($path, -6, 3);
         switch ($up) {
             case 3:
                 switch ($sex2) {
                     case 'M':
                         if ($bef_last === 'fat') {
                             return I18N::translateContext('great-grandfather’s brother', 'great-great-uncle');
                         } elseif ($bef_last === 'mot') {
                             return I18N::translateContext('great-grandmother’s brother', 'great-great-uncle');
                         } else {
                             return I18N::translateContext('great-grandparent’s brother', 'great-great-uncle');
                         }
                     case 'F':
                         return I18N::translate('great-great-aunt');
                     default:
                         return I18N::translate('great-great-aunt/uncle');
                 }
             case 4:
                 switch ($sex2) {
                     case 'M':
                         if ($bef_last === 'fat') {
                             return I18N::translateContext('great-great-grandfather’s brother', 'great-great-great-uncle');
                         } elseif ($bef_last === 'mot') {
                             return I18N::translateContext('great-great-grandmother’s brother', 'great-great-great-uncle');
                         } else {
                             return I18N::translateContext('great-great-grandparent’s brother', 'great-great-great-uncle');
                         }
                     case 'F':
                         return I18N::translate('great-great-great-aunt');
                     default:
                         return I18N::translate('great-great-great-aunt/uncle');
                 }
             case 5:
                 switch ($sex2) {
                     case 'M':
                         if ($bef_last === 'fat') {
                             return I18N::translateContext('great-great-great-grandfather’s brother', 'great ×4 uncle');
                         } elseif ($bef_last === 'mot') {
                             return I18N::translateContext('great-great-great-grandmother’s brother', 'great ×4 uncle');
                         } else {
                             return I18N::translateContext('great-great-great-grandparent’s brother', 'great ×4 uncle');
                         }
                     case 'F':
                         return I18N::translate('great ×4 aunt');
                     default:
                         return I18N::translate('great ×4 aunt/uncle');
                 }
             case 6:
                 switch ($sex2) {
                     case 'M':
                         if ($bef_last === 'fat') {
                             return I18N::translateContext('great ×4 grandfather’s brother', 'great ×5 uncle');
                         } elseif ($bef_last === 'mot') {
                             return I18N::translateContext('great ×4 grandmother’s brother', 'great ×5 uncle');
                         } else {
                             return I18N::translateContext('great ×4 grandparent’s brother', 'great ×5 uncle');
                         }
                     case 'F':
                         return I18N::translate('great ×5 aunt');
                     default:
                         return I18N::translate('great ×5 aunt/uncle');
                 }
             case 7:
                 switch ($sex2) {
                     case 'M':
                         if ($bef_last === 'fat') {
                             return I18N::translateContext('great ×5 grandfather’s brother', 'great ×6 uncle');
                         } elseif ($bef_last === 'mot') {
                             return I18N::translateContext('great ×5 grandmother’s brother', 'great ×6 uncle');
                         } else {
                             return I18N::translateContext('great ×5 grandparent’s brother', 'great ×6 uncle');
                         }
                     case 'F':
                         return I18N::translate('great ×6 aunt');
                     default:
                         return I18N::translate('great ×6 aunt/uncle');
                 }
             case 8:
                 switch ($sex2) {
                     case 'M':
                         if ($bef_last === 'fat') {
                             return I18N::translateContext('great ×6 grandfather’s brother', 'great ×7 uncle');
                         } elseif ($bef_last === 'mot') {
                             return I18N::translateContext('great ×6 grandmother’s brother', 'great ×7 uncle');
                         } else {
                             return I18N::translateContext('great ×6 grandparent’s brother', 'great ×7 uncle');
                         }
                     case 'F':
                         return I18N::translate('great ×7 aunt');
                     default:
                         return I18N::translate('great ×7 aunt/uncle');
                 }
             default:
                 // Different languages have different rules for naming generations.
                 // An English great ×12 uncle is a Danish great ×10 uncle.
                 //
                 // Need to find out which languages use which rules.
                 switch (WT_LOCALE) {
                     case 'da':
                         switch ($sex2) {
                             case 'M':
                                 return I18N::translate('great ×%s uncle', I18N::number($up - 4));
                             case 'F':
                                 return I18N::translate('great ×%s aunt', I18N::number($up - 4));
                             default:
                                 return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 4));
                         }
                     case 'pl':
                         switch ($sex2) {
                             case 'M':
                                 if ($bef_last === 'fat') {
                                     return I18N::translateContext('great ×(%s-1) grandfather’s brother', 'great ×%s uncle', I18N::number($up - 2));
                                 } elseif ($bef_last === 'mot') {
                                     return I18N::translateContext('great ×(%s-1) grandmother’s brother', 'great ×%s uncle', I18N::number($up - 2));
                                 } else {
                                     return I18N::translateContext('great ×(%s-1) grandparent’s brother', 'great ×%s uncle', I18N::number($up - 2));
                                 }
                             case 'F':
                                 return I18N::translate('great ×%s aunt', I18N::number($up - 2));
                             default:
                                 return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 2));
                         }
                     case 'it':
                         // Source: Michele Locati
                     // Source: Michele Locati
                     case 'en_AU':
                     case 'en_GB':
                     case 'en_US':
                     default:
                         switch ($sex2) {
                             case 'M':
                                 // I18N: if you need a different number for %s, contact the developers, as a code-change is required
                                 return I18N::translate('great ×%s uncle', I18N::number($up - 1));
                             case 'F':
                                 return I18N::translate('great ×%s aunt', I18N::number($up - 1));
                             default:
                                 return I18N::translate('great ×%s aunt/uncle', I18N::number($up - 1));
                         }
                 }
         }
     }
     if (preg_match('/^(?:bro|sis|sib)((?:son|dau|chi)+)$/', $path, $match)) {
         // direct descendants of siblings
         $down = strlen($match[1]) / 3 + 1;
         // Add one, as we count generations from the common ancestor
         $first = substr($path, 0, 3);
         switch ($down) {
             case 4:
                 switch ($sex2) {
                     case 'M':
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-grandson', 'great-great-nephew');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-grandson', 'great-great-nephew');
                         } else {
                             return I18N::translateContext('(a woman’s) great-great-nephew', 'great-great-nephew');
                         }
                     case 'F':
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-granddaughter', 'great-great-niece');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-granddaughter', 'great-great-niece');
                         } else {
                             return I18N::translateContext('(a woman’s) great-great-niece', 'great-great-niece');
                         }
                     default:
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-grandchild', 'great-great-nephew/niece');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-grandchild', 'great-great-nephew/niece');
                         } else {
                             return I18N::translateContext('(a woman’s) great-great-nephew/niece', 'great-great-nephew/niece');
                         }
                 }
             case 5:
                 switch ($sex2) {
                     case 'M':
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-great-grandson', 'great-great-great-nephew');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-great-grandson', 'great-great-great-nephew');
                         } else {
                             return I18N::translateContext('(a woman’s) great-great-great-nephew', 'great-great-great-nephew');
                         }
                     case 'F':
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-great-granddaughter', 'great-great-great-niece');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-great-granddaughter', 'great-great-great-niece');
                         } else {
                             return I18N::translateContext('(a woman’s) great-great-great-niece', 'great-great-great-niece');
                         }
                     default:
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-great-grandchild', 'great-great-great-nephew/niece');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-great-grandchild', 'great-great-great-nephew/niece');
                         } else {
                             return I18N::translateContext('(a woman’s) great-great-great-nephew/niece', 'great-great-great-nephew/niece');
                         }
                 }
             case 6:
                 switch ($sex2) {
                     case 'M':
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-great-great-grandson', 'great ×4 nephew');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-great-great-grandson', 'great ×4 nephew');
                         } else {
                             return I18N::translateContext('(a woman’s) great ×4 nephew', 'great ×4 nephew');
                         }
                     case 'F':
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-great-great-granddaughter', 'great ×4 niece');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-great-great-granddaughter', 'great ×4 niece');
                         } else {
                             return I18N::translateContext('(a woman’s) great ×4 niece', 'great ×4 niece');
                         }
                     default:
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great-great-great-grandchild', 'great ×4 nephew/niece');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great-great-great-grandchild', 'great ×4 nephew/niece');
                         } else {
                             return I18N::translateContext('(a woman’s) great ×4 nephew/niece', 'great ×4 nephew/niece');
                         }
                 }
             case 7:
                 switch ($sex2) {
                     case 'M':
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great ×4 grandson', 'great ×5 nephew');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great ×4 grandson', 'great ×5 nephew');
                         } else {
                             return I18N::translateContext('(a woman’s) great ×5 nephew', 'great ×5 nephew');
                         }
                     case 'F':
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great ×4 granddaughter', 'great ×5 niece');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great ×4 granddaughter', 'great ×5 niece');
                         } else {
                             return I18N::translateContext('(a woman’s) great ×5 niece', 'great ×5 niece');
                         }
                     default:
                         if ($first === 'bro' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) brother’s great ×4 grandchild', 'great ×5 nephew/niece');
                         } elseif ($first === 'sis' && $sex1 === 'M') {
                             return I18N::translateContext('(a man’s) sister’s great ×4 grandchild', 'great ×5 nephew/niece');
                         } else {
                             return I18N::translateContext('(a woman’s) great ×5 nephew/niece', 'great ×5 nephew/niece');
                         }
                 }
             default:
                 // Different languages have different rules for naming generations.
                 // An English great ×12 nephew is a Polish great ×11 nephew.
                 //
                 // Need to find out which languages use which rules.
                 switch (WT_LOCALE) {
                     case 'pl':
                         // Source: Lukasz Wilenski
                         switch ($sex2) {
                             case 'M':
                                 if ($first === 'bro' && $sex1 === 'M') {
                                     return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 3));
                                 } elseif ($first === 'sis' && $sex1 === 'M') {
                                     return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandson', 'great ×%s nephew', I18N::number($down - 3));
                                 } else {
                                     return I18N::translateContext('(a woman’s) great ×%s nephew', 'great ×%s nephew', I18N::number($down - 3));
                                 }
                             case 'F':
                                 if ($first === 'bro' && $sex1 === 'M') {
                                     return I18N::translateContext('(a man’s) brother’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 3));
                                 } elseif ($first === 'sis' && $sex1 === 'M') {
                                     return I18N::translateContext('(a man’s) sister’s great ×(%s-1) granddaughter', 'great ×%s niece', I18N::number($down - 3));
                                 } else {
                                     return I18N::translateContext('(a woman’s) great ×%s niece', 'great ×%s niece', I18N::number($down - 3));
                                 }
                             default:
                                 if ($first === 'bro' && $sex1 === 'M') {
                                     return I18N::translateContext('(a man’s) brother’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 3));
                                 } elseif ($first === 'sis' && $sex1 === 'M') {
                                     return I18N::translateContext('(a man’s) sister’s great ×(%s-1) grandchild', 'great ×%s nephew/niece', I18N::number($down - 3));
                                 } else {
                                     return I18N::translateContext('(a woman’s) great ×%s nephew/niece', 'great ×%s nephew/niece', I18N::number($down - 3));
                                 }
                         }
                     case 'he':
                         // Source: Meliza Amity
                         switch ($sex2) {
                             case 'M':
                                 return I18N::translate('great ×%s nephew', I18N::number($down - 1));
                             case 'F':
                                 return I18N::translate('great ×%s niece', I18N::number($down - 1));
                             default:
                                 return I18N::translate('great ×%s nephew/niece', I18N::number($down - 1));
                         }
                     case 'it':
                         // Source: Michele Locati.
                     // Source: Michele Locati.
                     case 'en_AU':
                     case 'en_GB':
                     case 'en_US':
                     default:
                         switch ($sex2) {
                             case 'M':
                                 // I18N: if you need a different number for %s, contact the developers, as a code-change is required
                                 return I18N::translate('great ×%s nephew', I18N::number($down - 2));
                             case 'F':
                                 return I18N::translate('great ×%s niece', I18N::number($down - 2));
                             default:
                                 return I18N::translate('great ×%s nephew/niece', I18N::number($down - 2));
                         }
                 }
         }
     }
     if (preg_match('/^((?:mot|fat|par)*)$/', $path, $match)) {
         // direct ancestors
         $up = strlen($match[1]) / 3;
         switch ($up) {
             case 4:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great-great-grandfather');
                     case 'F':
                         return I18N::translate('great-great-grandmother');
                     default:
                         return I18N::translate('great-great-grandparent');
                 }
             case 5:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great-great-great-grandfather');
                     case 'F':
                         return I18N::translate('great-great-great-grandmother');
                     default:
                         return I18N::translate('great-great-great-grandparent');
                 }
             case 6:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great ×4 grandfather');
                     case 'F':
                         return I18N::translate('great ×4 grandmother');
                     default:
                         return I18N::translate('great ×4 grandparent');
                 }
             case 7:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great ×5 grandfather');
                     case 'F':
                         return I18N::translate('great ×5 grandmother');
                     default:
                         return I18N::translate('great ×5 grandparent');
                 }
             case 8:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great ×6 grandfather');
                     case 'F':
                         return I18N::translate('great ×6 grandmother');
                     default:
                         return I18N::translate('great ×6 grandparent');
                 }
             case 9:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great ×7 grandfather');
                     case 'F':
                         return I18N::translate('great ×7 grandmother');
                     default:
                         return I18N::translate('great ×7 grandparent');
                 }
             default:
                 // Different languages have different rules for naming generations.
                 // An English great ×12 grandfather is a Danish great ×11 grandfather.
                 //
                 // Need to find out which languages use which rules.
                 switch (WT_LOCALE) {
                     case 'da':
                         // Source: Patrick Sorensen
                         switch ($sex2) {
                             case 'M':
                                 return I18N::translate('great ×%s grandfather', I18N::number($up - 3));
                             case 'F':
                                 return I18N::translate('great ×%s grandmother', I18N::number($up - 3));
                             default:
                                 return I18N::translate('great ×%s grandparent', I18N::number($up - 3));
                         }
                     case 'it':
                         // Source: Michele Locati
                     // Source: Michele Locati
                     case 'es':
                         // Source: Wes Groleau
                         switch ($sex2) {
                             case 'M':
                                 return I18N::translate('great ×%s grandfather', I18N::number($up));
                             case 'F':
                                 return I18N::translate('great ×%s grandmother', I18N::number($up));
                             default:
                                 return I18N::translate('great ×%s grandparent', I18N::number($up));
                         }
                     case 'fr':
                         // Source: Jacqueline Tetreault
                     // Source: Jacqueline Tetreault
                     case 'fr_CA':
                         switch ($sex2) {
                             case 'M':
                                 return I18N::translate('great ×%s grandfather', I18N::number($up - 1));
                             case 'F':
                                 return I18N::translate('great ×%s grandmother', I18N::number($up - 1));
                             default:
                                 return I18N::translate('great ×%s grandparent', I18N::number($up - 1));
                         }
                     case 'nn':
                         // Source: Hogne Røed Nilsen (https://bugs.launchpad.net/webtrees/+bug/1168553)
                     // Source: Hogne Røed Nilsen (https://bugs.launchpad.net/webtrees/+bug/1168553)
                     case 'nb':
                         switch ($sex2) {
                             case 'M':
                                 // I18N: if you need a different number for %s, contact the developers, as a code-change is required
                                 return I18N::translate('great ×%s grandfather', I18N::number($up - 3));
                             case 'F':
                                 return I18N::translate('great ×%s grandmother', I18N::number($up - 3));
                             default:
                                 return I18N::translate('great ×%s grandparent', I18N::number($up - 3));
                         }
                     case 'en_AU':
                     case 'en_GB':
                     case 'en_US':
                     default:
                         switch ($sex2) {
                             case 'M':
                                 // I18N: if you need a different number for %s, contact the developers, as a code-change is required
                                 return I18N::translate('great ×%s grandfather', I18N::number($up - 2));
                             case 'F':
                                 return I18N::translate('great ×%s grandmother', I18N::number($up - 2));
                             default:
                                 return I18N::translate('great ×%s grandparent', I18N::number($up - 2));
                         }
                 }
         }
     }
     if (preg_match('/^((?:son|dau|chi)*)$/', $path, $match)) {
         // direct descendants
         $up = strlen($match[1]) / 3;
         switch ($up) {
             case 4:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great-great-grandson');
                     case 'F':
                         return I18N::translate('great-great-granddaughter');
                     default:
                         return I18N::translate('great-great-grandchild');
                 }
             case 5:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great-great-great-grandson');
                     case 'F':
                         return I18N::translate('great-great-great-granddaughter');
                     default:
                         return I18N::translate('great-great-great-grandchild');
                 }
             case 6:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great ×4 grandson');
                     case 'F':
                         return I18N::translate('great ×4 granddaughter');
                     default:
                         return I18N::translate('great ×4 grandchild');
                 }
             case 7:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great ×5 grandson');
                     case 'F':
                         return I18N::translate('great ×5 granddaughter');
                     default:
                         return I18N::translate('great ×5 grandchild');
                 }
             case 8:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great ×6 grandson');
                     case 'F':
                         return I18N::translate('great ×6 granddaughter');
                     default:
                         return I18N::translate('great ×6 grandchild');
                 }
             case 9:
                 switch ($sex2) {
                     case 'M':
                         return I18N::translate('great ×7 grandson');
                     case 'F':
                         return I18N::translate('great ×7 granddaughter');
                     default:
                         return I18N::translate('great ×7 grandchild');
                 }
             default:
                 // Different languages have different rules for naming generations.
                 // An English great ×12 grandson is a Danish great ×11 grandson.
                 //
                 // Need to find out which languages use which rules.
                 switch (WT_LOCALE) {
                     case 'nn':
                         // Source: Hogne Røed Nilsen
                     // Source: Hogne Røed Nilsen
                     case 'nb':
                     case 'da':
                         // Source: Patrick Sorensen
                         switch ($sex2) {
                             case 'M':
                                 return I18N::translate('great ×%s grandson', I18N::number($up - 3));
                             case 'F':
                                 return I18N::translate('great ×%s granddaughter', I18N::number($up - 3));
                             default:
                                 return I18N::translate('great ×%s grandchild', I18N::number($up - 3));
                         }
                     case 'it':
                         // Source: Michele Locati
                     // Source: Michele Locati
                     case 'es':
                         // Source: Wes Groleau (adding doesn’t change behavior, but needs to be better researched)
                     // Source: Wes Groleau (adding doesn’t change behavior, but needs to be better researched)
                     case 'en_AU':
                     case 'en_GB':
                     case 'en_US':
                     default:
                         switch ($sex2) {
                             case 'M':
                                 // I18N: if you need a different number for %s, contact the developers, as a code-change is required
                                 return I18N::translate('great ×%s grandson', I18N::number($up - 2));
                             case 'F':
                                 return I18N::translate('great ×%s granddaughter', I18N::number($up - 2));
                             default:
                                 return I18N::translate('great ×%s grandchild', I18N::number($up - 2));
                         }
                 }
         }
     }
     if (preg_match('/^((?:mot|fat|par)+)(?:bro|sis|sib)((?:son|dau|chi)+)$/', $path, $match)) {
         // cousins in English
         $ascent = $match[1];
         $descent = $match[2];
         $up = strlen($ascent) / 3;
         $down = strlen($descent) / 3;
         $cousin = min($up, $down);
         // Moved out of switch (en/default case) so that
         $removed = abs($down - $up);
         // Spanish (and other languages) can use it, too.
         // Different languages have different rules for naming cousins.  For example,
         // an English “second cousin once removed” is a Polish “cousin of 7th degree”.
         //
         // Need to find out which languages use which rules.
         switch (WT_LOCALE) {
             case 'pl':
                 // Source: Lukasz Wilenski
                 return self::cousinName($up + $down + 2, $sex2);
             case 'it':
                 // Source: Michele Locati.  See italian_cousins_names.zip
                 // http://webtrees.net/forums/8-translation/1200-great-xn-grandparent?limit=6&start=6
                 return self::cousinName($up + $down - 3, $sex2);
             case 'es':
                 // Source: Wes Groleau.  See http://UniGen.us/Parentesco.html & http://UniGen.us/Parentesco-D.html
                 if ($down == $up) {
                     return self::cousinName($cousin, $sex2);
                 } elseif ($down < $up) {
                     return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sib' . $descent, null, null));
                 } else {
                     switch ($sex2) {
                         case 'M':
                             return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('bro' . $descent, null, null));
                         case 'F':
                             return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sis' . $descent, null, null));
                         default:
                             return self::cousinName2($cousin + 1, $sex2, self::getRelationshipNameFromPath('sib' . $descent, null, null));
                     }
                 }
             case 'en_AU':
                 // See: http://en.wikipedia.org/wiki/File:CousinTree.svg
             // See: http://en.wikipedia.org/wiki/File:CousinTree.svg
             case 'en_GB':
             case 'en_US':
             default:
                 switch ($removed) {
                     case 0:
                         return self::cousinName($cousin, $sex2);
                     case 1:
                         if ($up > $down) {
                             /* I18N: %s=“fifth cousin”, etc. http://www.ancestry.com/learn/library/article.aspx?article=2856 */
                             return I18N::translate('%s once removed ascending', self::cousinName($cousin, $sex2));
                         } else {
                             /* I18N: %s=“fifth cousin”, etc. http://www.ancestry.com/learn/library/article.aspx?article=2856 */
                             return I18N::translate('%s once removed descending', self::cousinName($cousin, $sex2));
                         }
                     case 2:
                         if ($up > $down) {
                             /* I18N: %s=“fifth cousin”, etc. */
                             return I18N::translate('%s twice removed ascending', self::cousinName($cousin, $sex2));
                         } else {
                             /* I18N: %s=“fifth cousin”, etc. */
                             return I18N::translate('%s twice removed descending', self::cousinName($cousin, $sex2));
                         }
                     case 3:
                         if ($up > $down) {
                             /* I18N: %s=“fifth cousin”, etc. */
                             return I18N::translate('%s three times removed ascending', self::cousinName($cousin, $sex2));
                         } else {
                             /* I18N: %s=“fifth cousin”, etc. */
                             return I18N::translate('%s three times removed descending', self::cousinName($cousin, $sex2));
                         }
                     default:
                         if ($up > $down) {
                             /* I18N: %1$s=“fifth cousin”, etc., %2$s>=4 */
                             return I18N::translate('%1$s %2$s times removed ascending', self::cousinName($cousin, $sex2), I18N::number($removed));
                         } else {
                             /* I18N: %1$s=“fifth cousin”, etc., %2$s>=4 */
                             return I18N::translate('%1$s %2$s times removed descending', self::cousinName($cousin, $sex2), I18N::number($removed));
                         }
                 }
         }
     }
     // Split the relationship into sub-relationships, e.g., third-cousin’s great-uncle.
     // Try splitting at every point, and choose the path with the shorted translated name.
     $relationship = null;
     $path1 = substr($path, 0, 3);
     $path2 = substr($path, 3);
     while ($path2) {
         $tmp = I18N::translate('%1$s’s %2$s', self::getRelationshipNameFromPath($path1, null, null), self::getRelationshipNameFromPath($path2, null, null));
         if (!$relationship || strlen($tmp) < strlen($relationship)) {
             $relationship = $tmp;
         }
         $path1 .= substr($path2, 0, 3);
         $path2 = substr($path2, 3);
     }
     return $relationship;
 }
Exemplo n.º 10
0
 /**
  * Add a person (and optionally their immediate family members) to the pids array
  *
  * @param Individual $person
  * @param bool $add_family
  *
  * @return array
  */
 private function addFamily(Individual $person, $add_family)
 {
     $xrefs = array();
     $xrefs[] = $person->getXref();
     if ($add_family) {
         foreach ($person->getSpouseFamilies() as $family) {
             $spouse = $family->getSpouse($person);
             if ($spouse) {
                 $xrefs[] = $spouse->getXref();
                 foreach ($family->getChildren() as $child) {
                     $xrefs[] = $child->getXref();
                 }
             }
         }
         foreach ($person->getChildFamilies() as $family) {
             foreach ($family->getSpouses() as $parent) {
                 $xrefs[] = $parent->getXref();
             }
             foreach ($family->getChildren() as $sibling) {
                 if ($person !== $sibling) {
                     $xrefs[] = $sibling->getXref();
                 }
             }
         }
     }
     return $xrefs;
 }
Exemplo n.º 11
0
 /**
  * Print a “Family Book” for an individual
  *
  * @param Individual $person
  * @param int    $descent_steps
  */
 public function printFamilyBook(Individual $person, $descent_steps)
 {
     if ($descent_steps == 0 || !$person->canShowName()) {
         return;
     }
     $families = $person->getSpouseFamilies();
     if ($families) {
         echo '<h3>', I18N::translate('Family of %s', $person->getFullName()), '</h3>', '<table class="t0"><tr><td class="tdmid">';
         $this->dgenerations = $this->generations;
         $this->printDescendency($person, 1);
         echo '</td><td class="tdmid">';
         $this->printPersonPedigree($person, 1);
         echo '</td></tr></table><br><br><hr style="page-break-after:always;"><br><br>';
         foreach ($families as $family) {
             foreach ($family->getChildren() as $child) {
                 $this->printFamilyBook($child, $descent_steps - 1);
             }
         }
     }
 }
Exemplo n.º 12
0
 /**
  * Calculates number of generations a person has
  *
  * @param Individual $individual Start individual
  * @param int        $depth      Pass in 0 and it calculates how far down descendency goes
  *
  * @return int Number of generations the descendency actually goes
  */
 private function maxDescendencyGenerations(Individual $individual, $depth)
 {
     if ($depth > $this->generations) {
         return $depth;
     }
     $maxdc = $depth;
     foreach ($individual->getSpouseFamilies() as $family) {
         foreach ($family->getChildren() as $child) {
             $dc = $this->maxDescendencyGenerations($child, $depth + 1);
             if ($dc >= $this->generations) {
                 return $dc;
             }
             if ($dc > $maxdc) {
                 $maxdc = $dc;
             }
         }
     }
     $maxdc++;
     if ($maxdc == 1) {
         $maxdc++;
     }
     return $maxdc;
 }
Exemplo n.º 13
0
 /**
  * Family links, to show in chart boxes.
  *
  * @param Individual $individual
  *
  * @return Menu[]
  */
 protected function individualBoxMenuFamilyLinks(Individual $individual)
 {
     $menus = array();
     foreach ($individual->getSpouseFamilies() as $family) {
         $menus[] = new Menu('<strong>' . I18N::translate('Family with spouse') . '</strong>', $family->getHtmlUrl());
         $spouse = $family->getSpouse($individual);
         if ($spouse && $spouse->canShowName()) {
             $menus[] = new Menu($spouse->getFullName(), $spouse->getHtmlUrl());
         }
         foreach ($family->getChildren() as $child) {
             if ($child->canShowName()) {
                 $menus[] = new Menu($child->getFullName(), $child->getHtmlUrl());
             }
         }
     }
     return $menus;
 }
Exemplo n.º 14
0
 /**
  * Display spouses.
  *
  * @param Individual $person
  * @param int        $generations
  *
  * @return string
  */
 public function loadSpouses(Individual $person, $generations)
 {
     $out = '';
     if ($person && $person->canShow()) {
         foreach ($person->getSpouseFamilies() as $family) {
             $out .= $this->getFamilyLi($family, $person, $generations - 1);
         }
     }
     if ($out) {
         return '<ul>' . $out . '</ul>';
     } else {
         return '';
     }
 }
Exemplo n.º 15
0
 /**
  * Find all the families that are descended from an individual.
  *
  * @param Individual $person
  * @param int        $n
  * @param Family[]   $array
  *
  * @return Family[]
  */
 public function familyDescendancy($person, $n, $array)
 {
     if ($n < 1) {
         return $array;
     }
     foreach ($person->getSpouseFamilies() as $family) {
         $array[$family->getXref()] = $family;
         foreach ($family->getChildren() as $child) {
             $array = $this->familyDescendancy($child, $n - 1, $array);
         }
     }
     return $array;
 }
Exemplo n.º 16
0
 /**
  * Format a family.
  *
  * @param Individual $person
  *
  * @return string
  */
 private function getFamily(Individual $person)
 {
     $html = '';
     if ($person->canShowName()) {
         foreach ($person->getSpouseFamilies() as $family) {
             $spouse = $family->getSpouse($person);
             $html .= $this->getHTML($spouse, true);
             $children = $family->getChildren();
             if (count($children) > 0) {
                 $html .= "<ul class='clist'>";
                 foreach ($children as $child) {
                     $html .= '<li>' . $this->getHTML($child) . '</li>';
                 }
                 $html .= '</ul>';
             }
         }
     }
     if (!$html) {
         $html = sprintf(self::MSG, I18N::translate('none'));
     }
     return sprintf(self::TTL, I18N::translate('Family')) . $html;
 }
Exemplo n.º 17
0
    /**
     * Build a map for an individual.
     *
     * @param Individual $indi
     */
    private function buildIndividualMap(Individual $indi)
    {
        $GM_MAX_ZOOM = $this->getSetting('GM_MAX_ZOOM');
        $facts = $indi->getFacts();
        foreach ($indi->getSpouseFamilies() as $family) {
            $facts = array_merge($facts, $family->getFacts());
            // Add birth of children from this family to the facts array
            foreach ($family->getChildren() as $child) {
                $facts[] = $child->getFirstFact('BIRT');
            }
        }
        $facts = array_values(array_filter($facts, function ($item) {
            // remove null facts (child without birth event) and
            // facts without places
            return !is_null($item) && !$item->getPlace()->isEmpty();
        }));
        Functions::sortFacts($facts);
        // At this point we have an array of valid sorted facts
        // so now build the data structures needed for the map display
        $events = array();
        $unique_places = array();
        foreach ($facts as $fact) {
            $place_data = $this->getPlaceData($fact);
            if (!empty($place_data)) {
                $index = $place_data['index'];
                if ($place_data['mapdata']['pl_zoom']) {
                    $GM_MAX_ZOOM = min($GM_MAX_ZOOM, $place_data['mapdata']['pl_zoom']);
                }
                // Produce the html for the sidebar
                $parent = $fact->getParent();
                if ($parent instanceof Individual && $parent->getXref() !== $indi->getXref()) {
                    // Childs birth
                    $name = '<a href="' . $parent->getHtmlUrl() . '">' . $parent->getFullName() . '</a>';
                    $label = strtr($parent->getSex(), array('F' => I18N::translate('Birth of a daughter'), 'M' => I18N::translate('Birth of a son'), 'U' => I18N::translate('Birth of a child')));
                    $class = 'person_box' . strtr($parent->getSex(), array('F' => 'F', 'M' => '', 'U' => 'NN'));
                    $evtStr = '<div class="gm-event">' . $label . '<div><strong>' . $name . '</strong></div>' . $fact->getDate()->display(true) . '</div>';
                } else {
                    $spouse = $parent instanceof Family ? $parent->getSpouse($indi) : null;
                    $name = $spouse ? '<a href="' . $spouse->getHtmlUrl() . '">' . $spouse->getFullName() . '</a>' : '';
                    $label = $fact->getLabel();
                    $class = 'optionbox';
                    if ($fact->getValue() && $spouse) {
                        $evtStr = '<div class="gm-event">' . $label . '<div>' . $fact->getValue() . '</div><strong>' . $name . '</strong>' . $fact->getDate()->display(true) . '</div>';
                    } elseif ($spouse) {
                        $evtStr = '<div class="gm-event">' . $label . '<div><strong>' . $name . '</strong></div>' . $fact->getDate()->display(true) . '</div>';
                    } elseif ($fact->getValue()) {
                        $evtStr = '<div class="gm-event">' . $label . '<div> ' . $fact->getValue() . '</div>' . $fact->getDate()->display(true) . '</div>';
                    } else {
                        $evtStr = '<div class="gm-event">' . $label . '<div>' . $fact->getDate()->display(true) . '</div></div>';
                    }
                }
                if (empty($unique_places[$index])) {
                    $unique_places[$index] = $place_data['mapdata'];
                }
                $unique_places[$index]['events'] .= $evtStr;
                $events[] = array('class' => $class, 'fact_label' => $label, 'date' => $fact->getDate()->display(true), 'info' => $fact->getValue(), 'name' => $name, 'place' => '<a href="' . $fact->getPlace()->getURL() . '">' . $fact->getPlace()->getFullName() . '</a>', 'placeid' => $index);
            }
        }
        if (!empty($events)) {
            $places = array_keys($unique_places);
            ob_start();
            // Create the normal googlemap sidebar of events and children
            echo '<div class="gm-events"><table class="facts_table">';
            foreach ($events as $event) {
                $index = array_search($event['placeid'], $places);
                echo '<tr>';
                echo '<td class="facts_label">';
                echo '<a href="#" onclick="return openInfowindow(\'', $index, '\')">', $event['fact_label'], '</a></td>';
                echo '<td class="', $event['class'], '">';
                if ($event['info']) {
                    echo '<div><span class="field">', Filter::escapeHtml($event['info']), '</span></div>';
                }
                if ($event['name']) {
                    echo '<div>', $event['name'], '</div>';
                }
                echo '<div>', $event['place'], '</div>';
                if ($event['date']) {
                    echo '<div>', $event['date'], '</div>';
                }
                echo '</td>';
                echo '</tr>';
            }
            echo '</table></div>';
            // *** ENABLE STREETVIEW ***
            $STREETVIEW = (bool) $this->getSetting('GM_USE_STREETVIEW');
            ?>

			<script>
				var map_center = new google.maps.LatLng(0, 0);
				var gmarkers   = [];
				var gicons     = [];
				var map        = null;
				var head       = '';
				var dir        = '';
				var svzoom     = '';

				var infowindow = new google.maps.InfoWindow({});

				gicons["red"] = {
					url:    "https://maps.google.com/mapfiles/marker.png",
					size:   google.maps.Size(20, 34),
					origin: google.maps.Point(0, 0),
					anchor: google.maps.Point(9, 34)
				};

				var iconImage = {
					url:    "https://maps.google.com/mapfiles/marker.png",
					size:   new google.maps.Size(20, 34),
					origin: new google.maps.Point(0, 0),
					anchor: new google.maps.Point(9, 34)
				};

				var iconShape = {
					coord: [9, 0, 6, 1, 4, 2, 2, 4, 0, 8, 0, 12, 1, 14, 2, 16, 5, 19, 7, 23, 8, 26, 9, 30, 9, 34, 11, 34, 11, 30, 12, 26, 13, 24, 14, 21, 16, 18, 18, 16, 20, 12, 20, 8, 18, 4, 16, 2, 15, 1, 13, 0],
					type:  "poly"
				};

				function getMarkerImage(iconColor) {
					if (typeof(iconColor) === 'undefined' || iconColor === null) {
						iconColor = 'red';
					}
					if (!gicons[iconColor]) {
						gicons[iconColor] = {
							url:    '//maps.google.com/mapfiles/marker' + iconColor + '.png',
							size:   new google.maps.Size(20, 34),
							origin: new google.maps.Point(0, 0),
							anchor: google.maps.Point(9, 34)
						};
					}
					return gicons[iconColor];
				}

				var sv2_bear = null;
				var sv2_elev = null;
				var sv2_zoom = null;
				var placer   = null;

				// A function to create the marker and set up the event window
				function createMarker(latlng, html, tooltip, sv_lati, sv_long, sv_bearing, sv_elevation, sv_zoom, sv_point, marker_icon) {
					// Use flag icon (if defined) instead of regular marker icon
					if (marker_icon) {
						var icon_image = {
							url:    WT_STATIC_URL + WT_MODULES_DIR + 'googlemap/' + marker_icon,
							size:   new google.maps.Size(25, 15),
							origin: new google.maps.Point(0, 0),
							anchor: new google.maps.Point(12, 15)
						};
					} else {
						var icon_image = getMarkerImage('red');
					}

					// Decide if marker point is Regular (latlng) or StreetView (sv_point) derived
					if (sv_point == '(0, 0)' || sv_point == '(null, null)') {
						placer = latlng;
					} else {
						placer = sv_point;
					}

					// Define the marker
					var marker = new google.maps.Marker({
						position: placer,
						icon:     icon_image,
						map:      map,
						title:    tooltip,
						zIndex:   Math.round(latlng.lat() * -100000) << 5
					});

					// Store the tab and event info as marker properties
					marker.sv_lati  = sv_lati;
					marker.sv_long  = sv_long;
					marker.sv_point = sv_point;

					if (sv_bearing == '') {
						marker.sv_bearing = 0;
					} else {
						marker.sv_bearing = sv_bearing;
					}
					if (sv_elevation == '') {
						marker.sv_elevation = 5;
					} else {
						marker.sv_elevation = sv_elevation;
					}
					if (sv_zoom == '' || sv_zoom == 0 || sv_zoom == 1) {
						marker.sv_zoom = 1.2;
					} else {
						marker.sv_zoom = sv_zoom;
					}

					marker.sv_latlng = new google.maps.LatLng(sv_lati, sv_long);
					gmarkers.push(marker);

					// Open infowindow when marker is clicked
					google.maps.event.addListener(marker, 'click', function() {
						infowindow.close();
						infowindow.setContent(html);
						infowindow.open(map, marker);

						var panoramaOptions = {
							position:          marker.position,
							mode:              'html5',
							navigationControl: false,
							linksControl:      false,
							addressControl:    false,
							pov:               {
								heading: sv_bearing,
								pitch:   sv_elevation,
								zoom:    sv_zoom
							}
						};

						// Tabs within the info-windows.
						<?php 
            if ($STREETVIEW) {
                ?>
						google.maps.event.addListener(infowindow, 'domready', function() {
							jQuery('#gm-tab-events').click(function () {
								document.getElementById("gm-tab-events").classList.add('gm-tab-active');
								document.getElementById("gm-tab-streetview").classList.remove('gm-tab-active');
								document.getElementById("gm-pane-events").style.display = 'block';
								document.getElementById("gm-pane-streetview").style.display = 'none';

								return false;
							});
							jQuery('#gm-tab-streetview').click(function () {
								document.getElementById("gm-tab-events").classList.remove('gm-tab-active');
								document.getElementById("gm-tab-streetview").classList.add('gm-tab-active');
								document.getElementById("gm-pane-events").style.display = 'none';
								document.getElementById("gm-pane-streetview").style.display = 'block';
								var panorama = new google.maps.StreetViewPanorama(document.querySelector(".gm-streetview"), panoramaOptions);

								return false;
							});
						});
						<?php 
            }
            ?>
					});
				}

				// Opens Marker infowindow when corresponding Sidebar item is clicked
				function openInfowindow(i) {
					infowindow.close();
					google.maps.event.trigger(gmarkers[i], 'click');
					return false;
				}

				function loadMap() {
					// Create the map and mapOptions
					var mapOptions = {
						zoom:                     7,
						center:                   map_center,
						mapTypeId:                google.maps.MapTypeId.<?php 
            echo $this->getSetting('GM_MAP_TYPE');
            ?>
,
						mapTypeControlOptions:    {
							style: google.maps.MapTypeControlStyle.DROPDOWN_MENU  // DEFAULT, DROPDOWN_MENU, HORIZONTAL_BAR
						},
						navigationControl:        true,
						navigationControlOptions: {
							position: google.maps.ControlPosition.TOP_RIGHT,  // BOTTOM, BOTTOM_LEFT, LEFT, TOP, etc
							style:    google.maps.NavigationControlStyle.SMALL  // ANDROID, DEFAULT, SMALL, ZOOM_PAN
						},
						streetViewControl:        true,
						scrollwheel:              true
					};
					map = new google.maps.Map(document.querySelector('.gm-map'), mapOptions);

					// Close any infowindow when map is clicked
					google.maps.event.addListener(map, 'click', function() {
						infowindow.close();
					});

					// Add the markers to the map

					// Group the markers by location
					var locations = <?php 
            echo json_encode($unique_places);
            ?>
;

					// Set the Marker bounds
					var bounds = new google.maps.LatLngBounds();
					var zoomLevel = <?php 
            echo $GM_MAX_ZOOM;
            ?>
;

					jQuery.each(locations, function(index, location) {
						var point     = new google.maps.LatLng(location.lat, location.lng); // Place Latitude, Longitude
						var sv_point  = new google.maps.LatLng(location.sv_lati, location.sv_long); // StreetView Latitude and Longitide
						var html      =
					    '<div class="gm-info-window">' +
					    '<div class="gm-info-window-header">' + location.place + '</div>' +
					    '<ul class="gm-tabs">' +
					    '<li class="gm-tab gm-tab-active" id="gm-tab-events"><a href="#"><?php 
            echo I18N::translate('Events');
            ?>
</a></li>' +
					    <?php 
            if ($STREETVIEW) {
                ?>
					    '<li class="gm-tab" id="gm-tab-streetview"><a href="#"><?php 
                echo I18N::translate('Google Street View™');
                ?>
</a></li>' +
					    <?php 
            }
            ?>
					    '</ul>' +
						  '<div class="gm-panes">' +
					    '<div class="gm-pane" id="gm-pane-events">' + location.events + '</div>' +
					    <?php 
            if ($STREETVIEW) {
                ?>
					    '<div class="gm-pane" id="gm-pane-streetview" hidden><div class="gm-streetview"></div></div>' +
					    <?php 
            }
            ?>
					    '</div>' +
					    '</div>';

						createMarker(point, html, location.tooltip, location.sv_lati, location.sv_long, location.sv_bearing, location.sv_elevation, location.sv_zoom, sv_point, location.pl_icon);
						// if streetview coordinates are available, use them for marker,
						// else use the place coordinates
						if (sv_point && sv_point != "(0, 0)") {
							var myLatLng = sv_point;
						} else {
							var myLatLng = point;
						}
						bounds.extend(myLatLng);
					}); // end loop through location markers

					map.setCenter(bounds.getCenter());
					map.fitBounds(bounds);
					google.maps.event.addListenerOnce(map, "bounds_changed", function(event) {
						if (this.getZoom() > zoomLevel) {
							this.setZoom(zoomLevel);
						}
					});
				} // end loadMap()

			</script>
			<?php 
            $html = ob_get_clean();
        } else {
            $html = '';
        }
        return $html;
    }
Exemplo n.º 18
0
 /** {@inheritdoc} */
 public function individualBoxMenuFamilyLinks(Individual $individual)
 {
     $menus = array();
     foreach ($individual->getSpouseFamilies() as $family) {
         $menus[] = new Menu(I18N::translate('Family with spouse'), $family->getHtmlUrl(), 'link-family');
         $spouse = $family->getSpouse($individual);
         if ($spouse && $spouse->canShowName()) {
             $menus[] = new Menu($spouse->getFullName(), $spouse->getHtmlUrl(), 'link-spouse');
         }
         foreach ($family->getChildren() as $child) {
             if ($child->canShowName()) {
                 $menus[] = new Menu($child->getFullName(), $child->getHtmlUrl(), 'link-child');
             }
         }
     }
     return $menus;
 }
Exemplo n.º 19
0
 /**
  * Find the current spouse family of an individual
  *
  * @param Individual $individual
  *
  * @return Family|null
  */
 public function spouseFamily(Individual $individual)
 {
     // Exclude families that were created after this census date
     $families = array();
     foreach ($individual->getSpouseFamilies() as $family) {
         if (Date::compare($family->getMarriageDate(), $this->date()) <= 0) {
             $families[] = $family;
         }
     }
     if (empty($families)) {
         return null;
     } else {
         usort($families, function (Family $x, Family $y) {
             return Date::compare($x->getMarriageDate(), $y->getMarriageDate());
         });
         return end($families);
     }
 }