xref: /webtrees/app/Gedcom.php (revision 367b2b3288a62d2e078b1e0e4ec028013686c956)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2022 webtrees development team
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees;
21
22use Fisharebest\Webtrees\Contracts\ElementInterface;
23use Fisharebest\Webtrees\Elements\AddressCity;
24use Fisharebest\Webtrees\Elements\AddressCountry;
25use Fisharebest\Webtrees\Elements\AddressEmail;
26use Fisharebest\Webtrees\Elements\AddressFax;
27use Fisharebest\Webtrees\Elements\AddressLine;
28use Fisharebest\Webtrees\Elements\AddressLine1;
29use Fisharebest\Webtrees\Elements\AddressLine2;
30use Fisharebest\Webtrees\Elements\AddressLine3;
31use Fisharebest\Webtrees\Elements\AddressPostalCode;
32use Fisharebest\Webtrees\Elements\AddressState;
33use Fisharebest\Webtrees\Elements\AddressWebPage;
34use Fisharebest\Webtrees\Elements\AdoptedByWhichParent;
35use Fisharebest\Webtrees\Elements\Adoption;
36use Fisharebest\Webtrees\Elements\AdultChristening;
37use Fisharebest\Webtrees\Elements\AgeAtEvent;
38use Fisharebest\Webtrees\Elements\AncestralFileNumber;
39use Fisharebest\Webtrees\Elements\Annulment;
40use Fisharebest\Webtrees\Elements\ApprovedSystemId;
41use Fisharebest\Webtrees\Elements\AutomatedRecordId;
42use Fisharebest\Webtrees\Elements\Baptism;
43use Fisharebest\Webtrees\Elements\BarMitzvah;
44use Fisharebest\Webtrees\Elements\BasMitzvah;
45use Fisharebest\Webtrees\Elements\Birth;
46use Fisharebest\Webtrees\Elements\Blessing;
47use Fisharebest\Webtrees\Elements\Burial;
48use Fisharebest\Webtrees\Elements\CasteName;
49use Fisharebest\Webtrees\Elements\CauseOfEvent;
50use Fisharebest\Webtrees\Elements\Census;
51use Fisharebest\Webtrees\Elements\CertaintyAssessment;
52use Fisharebest\Webtrees\Elements\Change;
53use Fisharebest\Webtrees\Elements\ChangeDate;
54use Fisharebest\Webtrees\Elements\CharacterSet;
55use Fisharebest\Webtrees\Elements\ChildLinkageStatus;
56use Fisharebest\Webtrees\Elements\Christening;
57use Fisharebest\Webtrees\Elements\Confirmation;
58use Fisharebest\Webtrees\Elements\ContentDescription;
59use Fisharebest\Webtrees\Elements\Coordinates;
60use Fisharebest\Webtrees\Elements\CopyrightFile;
61use Fisharebest\Webtrees\Elements\CopyrightSourceData;
62use Fisharebest\Webtrees\Elements\CountOfChildren;
63use Fisharebest\Webtrees\Elements\CountOfMarriages;
64use Fisharebest\Webtrees\Elements\Cremation;
65use Fisharebest\Webtrees\Elements\CustomElement;
66use Fisharebest\Webtrees\Elements\CustomEvent;
67use Fisharebest\Webtrees\Elements\CustomFact;
68use Fisharebest\Webtrees\Elements\CustomFamilyEvent;
69use Fisharebest\Webtrees\Elements\CustomIndividualEvent;
70use Fisharebest\Webtrees\Elements\DateLdsOrd;
71use Fisharebest\Webtrees\Elements\DateValue;
72use Fisharebest\Webtrees\Elements\Death;
73use Fisharebest\Webtrees\Elements\DescriptiveTitle;
74use Fisharebest\Webtrees\Elements\Divorce;
75use Fisharebest\Webtrees\Elements\DivorceFiled;
76use Fisharebest\Webtrees\Elements\Emigration;
77use Fisharebest\Webtrees\Elements\EmptyElement;
78use Fisharebest\Webtrees\Elements\Engagement;
79use Fisharebest\Webtrees\Elements\EntryRecordingDate;
80use Fisharebest\Webtrees\Elements\EventAttributeType;
81use Fisharebest\Webtrees\Elements\EventOrFactClassification;
82use Fisharebest\Webtrees\Elements\EventsRecorded;
83use Fisharebest\Webtrees\Elements\EventTypeCitedFrom;
84use Fisharebest\Webtrees\Elements\FamilyCensus;
85use Fisharebest\Webtrees\Elements\FamilyRecord;
86use Fisharebest\Webtrees\Elements\FamilyResidence;
87use Fisharebest\Webtrees\Elements\FamilySearchFamilyTreeId;
88use Fisharebest\Webtrees\Elements\FamilyStatusText;
89use Fisharebest\Webtrees\Elements\FileName;
90use Fisharebest\Webtrees\Elements\FirstCommunion;
91use Fisharebest\Webtrees\Elements\Form;
92use Fisharebest\Webtrees\Elements\GedcomElement;
93use Fisharebest\Webtrees\Elements\GenerationsOfAncestors;
94use Fisharebest\Webtrees\Elements\GenerationsOfDescendants;
95use Fisharebest\Webtrees\Elements\GovIdentifier;
96use Fisharebest\Webtrees\Elements\Graduation;
97use Fisharebest\Webtrees\Elements\HeaderRecord;
98use Fisharebest\Webtrees\Elements\HierarchicalRelationship;
99use Fisharebest\Webtrees\Elements\Immigration;
100use Fisharebest\Webtrees\Elements\IndividualRecord;
101use Fisharebest\Webtrees\Elements\LanguageId;
102use Fisharebest\Webtrees\Elements\LdsBaptism;
103use Fisharebest\Webtrees\Elements\LdsBaptismDateStatus;
104use Fisharebest\Webtrees\Elements\LdsChildSealing;
105use Fisharebest\Webtrees\Elements\LdsChildSealingDateStatus;
106use Fisharebest\Webtrees\Elements\LdsConfirmation;
107use Fisharebest\Webtrees\Elements\LdsEndowment;
108use Fisharebest\Webtrees\Elements\LdsEndowmentDateStatus;
109use Fisharebest\Webtrees\Elements\LdsSpouseSealing;
110use Fisharebest\Webtrees\Elements\LdsSpouseSealingDateStatus;
111use Fisharebest\Webtrees\Elements\LocationRecord;
112use Fisharebest\Webtrees\Elements\MaidenheadLocator;
113use Fisharebest\Webtrees\Elements\Marriage;
114use Fisharebest\Webtrees\Elements\MarriageBanns;
115use Fisharebest\Webtrees\Elements\MarriageContract;
116use Fisharebest\Webtrees\Elements\MarriageLicence;
117use Fisharebest\Webtrees\Elements\MarriageSettlement;
118use Fisharebest\Webtrees\Elements\MarriageType;
119use Fisharebest\Webtrees\Elements\MediaRecord;
120use Fisharebest\Webtrees\Elements\MultimediaFileReference;
121use Fisharebest\Webtrees\Elements\MultimediaFormat;
122use Fisharebest\Webtrees\Elements\NameOfBusiness;
123use Fisharebest\Webtrees\Elements\NameOfFamilyFile;
124use Fisharebest\Webtrees\Elements\NameOfProduct;
125use Fisharebest\Webtrees\Elements\NameOfRepository;
126use Fisharebest\Webtrees\Elements\NameOfSourceData;
127use Fisharebest\Webtrees\Elements\NamePersonal;
128use Fisharebest\Webtrees\Elements\NamePhoneticVariation;
129use Fisharebest\Webtrees\Elements\NamePieceGiven;
130use Fisharebest\Webtrees\Elements\NamePieceNickname;
131use Fisharebest\Webtrees\Elements\NamePiecePrefix;
132use Fisharebest\Webtrees\Elements\NamePieceSuffix;
133use Fisharebest\Webtrees\Elements\NamePieceSurname;
134use Fisharebest\Webtrees\Elements\NamePieceSurnamePrefix;
135use Fisharebest\Webtrees\Elements\NameRomanizedVariation;
136use Fisharebest\Webtrees\Elements\NameType;
137use Fisharebest\Webtrees\Elements\NationalIdNumber;
138use Fisharebest\Webtrees\Elements\NationOrTribalOrigin;
139use Fisharebest\Webtrees\Elements\Naturalization;
140use Fisharebest\Webtrees\Elements\NobilityTypeTitle;
141use Fisharebest\Webtrees\Elements\NoteRecord;
142use Fisharebest\Webtrees\Elements\NoteStructure;
143use Fisharebest\Webtrees\Elements\Occupation;
144use Fisharebest\Webtrees\Elements\OrdinanceProcessFlag;
145use Fisharebest\Webtrees\Elements\Ordination;
146use Fisharebest\Webtrees\Elements\PafUid;
147use Fisharebest\Webtrees\Elements\PedigreeLinkageType;
148use Fisharebest\Webtrees\Elements\PermanentRecordFileNumber;
149use Fisharebest\Webtrees\Elements\PhoneNumber;
150use Fisharebest\Webtrees\Elements\PhoneticType;
151use Fisharebest\Webtrees\Elements\PhysicalDescription;
152use Fisharebest\Webtrees\Elements\PlaceHierarchy;
153use Fisharebest\Webtrees\Elements\PlaceLatitude;
154use Fisharebest\Webtrees\Elements\PlaceLivingOrdinance;
155use Fisharebest\Webtrees\Elements\PlaceLongtitude;
156use Fisharebest\Webtrees\Elements\PlaceName;
157use Fisharebest\Webtrees\Elements\PlacePhoneticVariation;
158use Fisharebest\Webtrees\Elements\PlaceRomanizedVariation;
159use Fisharebest\Webtrees\Elements\Possessions;
160use Fisharebest\Webtrees\Elements\Probate;
161use Fisharebest\Webtrees\Elements\PublicationDate;
162use Fisharebest\Webtrees\Elements\ReceivingSystemName;
163use Fisharebest\Webtrees\Elements\RelationIsDescriptor;
164use Fisharebest\Webtrees\Elements\ReligiousAffiliation;
165use Fisharebest\Webtrees\Elements\RepositoryRecord;
166use Fisharebest\Webtrees\Elements\ResearchTask;
167use Fisharebest\Webtrees\Elements\ResearchTaskPriority;
168use Fisharebest\Webtrees\Elements\ResearchTaskStatus;
169use Fisharebest\Webtrees\Elements\ResearchTaskType;
170use Fisharebest\Webtrees\Elements\Residence;
171use Fisharebest\Webtrees\Elements\ResponsibleAgency;
172use Fisharebest\Webtrees\Elements\RestrictionNotice;
173use Fisharebest\Webtrees\Elements\Retirement;
174use Fisharebest\Webtrees\Elements\RoleInEvent;
175use Fisharebest\Webtrees\Elements\RomanizedType;
176use Fisharebest\Webtrees\Elements\ScholasticAchievement;
177use Fisharebest\Webtrees\Elements\SexValue;
178use Fisharebest\Webtrees\Elements\SexXValue;
179use Fisharebest\Webtrees\Elements\SocialSecurityNumber;
180use Fisharebest\Webtrees\Elements\SourceCallNumber;
181use Fisharebest\Webtrees\Elements\SourceData;
182use Fisharebest\Webtrees\Elements\SourceFiledByEntry;
183use Fisharebest\Webtrees\Elements\SourceJurisdictionPlace;
184use Fisharebest\Webtrees\Elements\SourceMediaType;
185use Fisharebest\Webtrees\Elements\SourceOriginator;
186use Fisharebest\Webtrees\Elements\SourcePublicationFacts;
187use Fisharebest\Webtrees\Elements\SourceRecord;
188use Fisharebest\Webtrees\Elements\SubmissionRecord;
189use Fisharebest\Webtrees\Elements\SubmitterName;
190use Fisharebest\Webtrees\Elements\SubmitterRecord;
191use Fisharebest\Webtrees\Elements\SubmitterRegisteredRfn;
192use Fisharebest\Webtrees\Elements\SubmitterText;
193use Fisharebest\Webtrees\Elements\TempleCode;
194use Fisharebest\Webtrees\Elements\TextFromSource;
195use Fisharebest\Webtrees\Elements\TimeValue;
196use Fisharebest\Webtrees\Elements\TransmissionDate;
197use Fisharebest\Webtrees\Elements\UserReferenceNumber;
198use Fisharebest\Webtrees\Elements\UserReferenceType;
199use Fisharebest\Webtrees\Elements\VersionNumber;
200use Fisharebest\Webtrees\Elements\WebtreesUser;
201use Fisharebest\Webtrees\Elements\WhereWithinSource;
202use Fisharebest\Webtrees\Elements\Will;
203use Fisharebest\Webtrees\Elements\XrefAssociate;
204use Fisharebest\Webtrees\Elements\XrefFamily;
205use Fisharebest\Webtrees\Elements\XrefIndividual;
206use Fisharebest\Webtrees\Elements\XrefLocation;
207use Fisharebest\Webtrees\Elements\XrefMedia;
208use Fisharebest\Webtrees\Elements\XrefRepository;
209use Fisharebest\Webtrees\Elements\XrefSource;
210use Fisharebest\Webtrees\Elements\XrefSubmission;
211use Fisharebest\Webtrees\Elements\XrefSubmitter;
212
213/**
214 * GEDCOM 5.5.1 specification
215 */
216class Gedcom
217{
218    // 255 less the EOL character.
219    public const LINE_LENGTH = 253;
220
221    // Gedcom tags which indicate the start of life.
222    public const BIRTH_EVENTS = ['BIRT', 'CHR', 'BAPM'];
223
224    // Gedcom tags which indicate the end of life.
225    public const DEATH_EVENTS = ['DEAT', 'BURI', 'CREM'];
226
227    // Gedcom tags which indicate the start of a relationship.
228    public const MARRIAGE_EVENTS = ['MARR', '_NMR'];
229
230    // Gedcom tags which indicate the end of a relationship.
231    public const DIVORCE_EVENTS = ['DIV', 'ANUL', '_SEPR'];
232
233    // Regular expression to match a GEDCOM tag.
234    public const REGEX_TAG = '[_A-Z][_A-Z0-9]*';
235
236    // Regular expression to match a GEDCOM XREF.
237    public const REGEX_XREF = '[A-Za-z0-9:_.-]{1,20}';
238
239    // Separates the parts of a place name.
240    public const PLACE_SEPARATOR = ', ';
241
242    // Regex to match a (badly formed) GEDCOM place separator.
243    public const PLACE_SEPARATOR_REGEX = '/ *,[, ]*/';
244
245    // LATI and LONG tags
246    public const LATITUDE_NORTH = 'N';
247    public const LATITUDE_SOUTH = 'S';
248    public const LONGITUDE_EAST = 'E';
249    public const LONGITUDE_WEST = 'W';
250
251    // Not all record types allow a CHAN event.
252    public const RECORDS_WITH_CHAN = [
253        Family::RECORD_TYPE,
254        Individual::RECORD_TYPE,
255        Media::RECORD_TYPE,
256        Note::RECORD_TYPE,
257        Repository::RECORD_TYPE,
258        Source::RECORD_TYPE,
259        Submitter::RECORD_TYPE,
260    ];
261
262    // These preferences control multiple tag definitions
263    public const HIDDEN_TAGS = [
264        // Individual names
265        'NAME_NPFX' => ['INDI:NAME:NPFX', 'INDI:NAME:FONE:NPFX', 'INDI:NAME:ROMN:NPFX'],
266        'NAME_SPFX' => ['INDI:NAME:SPFX', 'INDI:NAME:FONE:SPFX', 'INDI:NAME:ROMN:SPFX'],
267        'NAME_NSFX' => ['INDI:NAME:NSFX', 'INDI:NAME:FONE:NSFX', 'INDI:NAME:ROMN:NSFX'],
268        'NAME_NICK' => ['INDI:NAME:NICK', 'INDI:NAME:FONE:NICK', 'INDI:NAME:ROMN:NICK'],
269        'NAME_FONE' => ['INDI:NAME:FONE'],
270        'NAME_ROMN' => ['INDI:NAME:ROMN'],
271        'NAME_NOTE' => ['INDI:NAME:NOTE'],
272        'NAME_SOUR' => ['INDI:NAME:SOUR'],
273        // Places
274        'PLAC_MAP'  => ['PLAC:MAP'],
275        'PLAC_FONE' => ['PLAC:FONE'],
276        'PLAC_ROMN' => ['PLAC:ROMN'],
277        'PLAC_FORM' => ['PLAC:FORM', 'HEAD:PLAC'],
278        'PLAC_NOTE' => ['PLAC:NOTE'],
279        // Addresses
280        'ADDR_FAX'  => ['FAX'],
281        'ADDR_PHON' => ['PHON'],
282        'ADDR_WWW'  => ['WWW'],
283        // Source citations
284        'SOUR_EVEN' => [':SOUR:EVEN'],
285        'SOUR_DATE' => [':SOUR:DATA:DATE'],
286        'SOUR_NOTE' => [':SOUR:NOTE'],
287        'SOUR_QUAY' => [':SOUR:QUAY'],
288        // Sources
289        'SOUR_DATA' => ['SOUR:DATA:EVEN', 'SOUR:DATA:AGNC', 'SOUR:DATA:NOTE'],
290        // Individuals
291        'BIRT_FAMC' => ['INDI:BIRT:FAMC'],
292        'RELI'      => ['INDI:RELI'],
293        'BAPM'      => ['INDI:BAPM'],
294        'CHR'       => ['INDI:CHR', 'INDI:CHRA'],
295        'FCOM'      => ['INDI:FCOM', 'INDI:CONF'],
296        'ORDN'      => ['INDI:ORDN'],
297        'BARM'      => ['INDI:BARM', 'INDI:BASM'],
298        'ALIA'      => ['INDI:ALIA'],
299        'ASSO'      => ['INDI:ASSO'],
300        // Families
301        'ENGA'      => ['FAM:ENGA'],
302        'MARB'      => ['FAM:MARB'],
303        'MARC'      => ['FAM:MARC'],
304        'MARL'      => ['FAM:MARL'],
305        'MARS'      => ['FAM:MARS'],
306        'ANUL'      => ['FAM:ANUL'],
307        'DIVF'      => ['FAM:DIVF'],
308        'FAM_RESI'  => ['FAM:RESI'],
309        'FAM_CENS'  => ['FAM:CENS'],
310        // LDS church
311        'LDS'       => ['INDI:BAPL', 'INDI:CONL', 'INDI:ENDL', 'INDI:SLGC', 'FAM:SLGS', 'HEAD:SUBN'],
312        // Identifiers
313        'AFN'       => ['INDI:AFN'],
314        'IDNO'      => ['INDI:IDNO'],
315        'SSN'       => ['INDI:SSN'],
316        'RFN'       => ['RFN'],
317        'REFN'      => ['REFN'],
318        'RIN'       => ['RIN'],
319        // Submitters
320        'SUBM'      => ['INDI:SUBM', 'FAM:SUBM'],
321        'ANCI'      => ['INDI:ANCI', 'INDI:DESI'],
322    ];
323
324    // Custom GEDCOM tags that can be created in webtrees.
325    public const CUSTOM_FAMILY_TAGS = [
326        '_COML',
327        '_MARI',
328        '_MBON',
329        '_NMR',
330        '_SEPR',
331    ];
332
333    public const CUSTOM_INDIVIDUAL_TAGS = [
334        '_BRTM',
335        '_CIRC',
336        '_DEG',
337        '_DNA',
338        '_EXCM',
339        '_EYEC',
340        '_FNRL',
341        '_FSFTID',
342        '_HAIR',
343        '_HEIG',
344        '_INTE',
345        '_MDCL',
346        '_MEDC',
347        '_MILI',
348        '_MILT',
349        '_NAMS',
350        '_PRMN',
351        '_WEIG',
352        '_YART',
353    ];
354
355    /**
356     * Definitions for GEDCOM 5.5.1.
357     *
358     * @return array<string,ElementInterface>
359     */
360    private function gedcom551Tags(): array
361    {
362        return [
363            'FAM'                      => new FamilyRecord(I18N::translate('Family')),
364            'FAM:*:ADDR'               => new AddressLine(I18N::translate('Address')),
365            'FAM:*:ADDR:ADR1'          => new AddressLine1(I18N::translate('Address line 1')),
366            'FAM:*:ADDR:ADR2'          => new AddressLine2(I18N::translate('Address line 2')),
367            'FAM:*:ADDR:ADR3'          => new AddressLine3(I18N::translate('Address line 3')),
368            'FAM:*:ADDR:CITY'          => new AddressCity(I18N::translate('City')),
369            'FAM:*:ADDR:CTRY'          => new AddressCountry(I18N::translate('Country')),
370            'FAM:*:ADDR:POST'          => new AddressPostalCode(I18N::translate('Postal code')),
371            'FAM:*:ADDR:STAE'          => new AddressState(I18N::translate('State')),
372            'FAM:*:AGNC'               => new ResponsibleAgency(I18N::translate('Agency')),
373            'FAM:*:CAUS'               => new CauseOfEvent(I18N::translate('Cause')),
374            'FAM:*:DATE'               => new DateValue(I18N::translate('Date')),
375            'FAM:*:EMAIL'              => new AddressEmail(I18N::translate('Email address')),
376            'FAM:*:FAX'                => new AddressFax(I18N::translate('Fax')),
377            'FAM:*:HUSB'               => new EmptyElement(I18N::translate('Husband'), ['AGE' => '0:1']),
378            'FAM:*:HUSB:AGE'           => new AgeAtEvent(I18N::translate('Husband’s age')),
379            'FAM:*:NOTE'               => new NoteStructure(I18N::translate('Note')),
380            'FAM:*:OBJE'               => new XrefMedia(I18N::translate('Media object')),
381            'FAM:*:PHON'               => new PhoneNumber(I18N::translate('Phone')),
382            'FAM:*:PLAC'               => new PlaceName(I18N::translate('Place')),
383            'FAM:*:PLAC:FONE'          => new PlacePhoneticVariation(I18N::translate('Phonetic place')),
384            'FAM:*:PLAC:FONE:TYPE'     => new PhoneticType(I18N::translate('Type')),
385            'FAM:*:PLAC:FORM'          => new PlaceHierarchy(I18N::translate('Format')),
386            'FAM:*:PLAC:MAP'           => new Coordinates(I18N::translate('Coordinates')),
387            'FAM:*:PLAC:MAP:LATI'      => new PlaceLatitude(I18N::translate('Latitude')),
388            'FAM:*:PLAC:MAP:LONG'      => new PlaceLongtitude(I18N::translate('Longitude')),
389            'FAM:*:PLAC:NOTE'          => new NoteStructure(I18N::translate('Note')),
390            'FAM:*:PLAC:ROMN'          => new PlaceRomanizedVariation(I18N::translate('Romanized place')),
391            'FAM:*:PLAC:ROMN:TYPE'     => new RomanizedType(I18N::translate('Type')),
392            'FAM:*:RELI'               => new ReligiousAffiliation(I18N::translate('Religion'), []),
393            'FAM:*:RESN'               => new RestrictionNotice(I18N::translate('Restriction')),
394            'FAM:*:SOUR'               => new XrefSource(I18N::translate('Source citation')),
395            'FAM:*:SOUR:DATA'          => new SourceData(I18N::translate('Data')),
396            'FAM:*:SOUR:DATA:DATE'     => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
397            'FAM:*:SOUR:DATA:TEXT'     => new TextFromSource(I18N::translate('Text')),
398            'FAM:*:SOUR:EVEN'          => new EventTypeCitedFrom(I18N::translate('Event')),
399            'FAM:*:SOUR:EVEN:ROLE'     => new RoleInEvent(I18N::translate('Role')),
400            'FAM:*:SOUR:NOTE'          => new NoteStructure(I18N::translate('Note')),
401            'FAM:*:SOUR:OBJE'          => new XrefMedia(I18N::translate('Media object')),
402            'FAM:*:SOUR:PAGE'          => new WhereWithinSource(I18N::translate('Citation details')),
403            'FAM:*:SOUR:QUAY'          => new CertaintyAssessment(I18N::translate('Quality of data')),
404            'FAM:*:TYPE'               => new EventOrFactClassification(I18N::translate('Type')),
405            'FAM:*:WIFE'               => new EmptyElement(I18N::translate('Wife'), ['AGE' => '0:1']),
406            'FAM:*:WIFE:AGE'           => new AgeAtEvent(I18N::translate('Wife’s age')),
407            'FAM:*:WWW'                => new AddressWebPage(I18N::translate('URL')),
408            'FAM:ANUL'                 => new Annulment(I18N::translate('Annulment')),
409            'FAM:CENS'                 => new FamilyCensus(I18N::translate('Family census')),
410            'FAM:CHAN'                 => new Change(I18N::translate('Last change')),
411            'FAM:CHAN:DATE'            => new ChangeDate(I18N::translate('Date of last change')),
412            'FAM:CHAN:DATE:TIME'       => new TimeValue(I18N::translate('Time of last change')),
413            'FAM:CHIL'                 => new XrefIndividual(I18N::translate('Child')),
414            'FAM:DIV'                  => new Divorce(I18N::translate('Divorce')),
415            'FAM:DIV:DATE'             => new DateValue(I18N::translate('Date of divorce')),
416            'FAM:DIVF'                 => new DivorceFiled(I18N::translate('Divorce filed')),
417            'FAM:ENGA'                 => new Engagement(I18N::translate('Engagement')),
418            'FAM:ENGA:DATE'            => new DateValue(I18N::translate('Date of engagement')),
419            'FAM:ENGA:PLAC'            => new PlaceName(I18N::translate('Place of engagement')),
420            'FAM:EVEN'                 => new CustomFamilyEvent(I18N::translate('Event')),
421            'FAM:EVEN:TYPE'            => new EventAttributeType(I18N::translate('Type of event')),
422            'FAM:HUSB'                 => new XrefIndividual(I18N::translate('Husband')),
423            'FAM:MARB'                 => new MarriageBanns(I18N::translate('Marriage banns')),
424            'FAM:MARB:DATE'            => new DateValue(I18N::translate('Date of marriage banns')),
425            'FAM:MARB:PLAC'            => new PlaceName(I18N::translate('Place of marriage banns')),
426            'FAM:MARC'                 => new MarriageContract(I18N::translate('Marriage contract')),
427            'FAM:MARL'                 => new MarriageLicence(I18N::translate('Marriage license')),
428            'FAM:MARR'                 => new Marriage(I18N::translate('Marriage')),
429            'FAM:MARR:DATE'            => new DateValue(I18N::translate('Date of marriage')),
430            'FAM:MARR:PLAC'            => new PlaceName(I18N::translate('Place of marriage')),
431            'FAM:MARR:TYPE'            => new MarriageType(I18N::translate('Type of marriage')),
432            'FAM:MARS'                 => new MarriageSettlement(I18N::translate('Marriage settlement')),
433            'FAM:NCHI'                 => new CountOfChildren(I18N::translate('Number of children')),
434            'FAM:NOTE'                 => new NoteStructure(I18N::translate('Note')),
435            'FAM:OBJE'                 => new XrefMedia(I18N::translate('Media object')),
436            'FAM:REFN'                 => new UserReferenceNumber(I18N::translate('Reference number')),
437            'FAM:REFN:TYPE'            => new UserReferenceType(I18N::translate('Type of reference number')),
438            'FAM:RESI'                 => new FamilyResidence(I18N::translate('Family residence')),
439            'FAM:RESN'                 => new RestrictionNotice(I18N::translate('Restriction')),
440            'FAM:RIN'                  => new AutomatedRecordId(I18N::translate('Record ID number')),
441            'FAM:SLGS'                 => new LdsSpouseSealing(I18N::translate('LDS spouse sealing')),
442            'FAM:SLGS:DATE'            => new DateLdsOrd(I18N::translate('Date of LDS spouse sealing')),
443            'FAM:SLGS:PLAC'            => new PlaceLivingOrdinance(I18N::translate('Place of LDS spouse sealing')),
444            'FAM:SLGS:STAT'            => new LdsSpouseSealingDateStatus(I18N::translate('Status')),
445            'FAM:SLGS:STAT:DATE'       => new ChangeDate(I18N::translate('Status change date')),
446            'FAM:SLGS:TEMP'            => new TempleCode(I18N::translate('Temple')),
447            'FAM:SOUR'                 => new XrefSource(I18N::translate('Source citation')),
448            'FAM:SOUR:DATA'            => new SourceData(I18N::translate('Data')),
449            'FAM:SOUR:DATA:DATE'       => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
450            'FAM:SOUR:DATA:TEXT'       => new TextFromSource(I18N::translate('Text')),
451            'FAM:SOUR:EVEN'            => new EventTypeCitedFrom(I18N::translate('Event')),
452            'FAM:SOUR:EVEN:ROLE'       => new RoleInEvent(I18N::translate('Role')),
453            'FAM:SOUR:NOTE'            => new NoteStructure(I18N::translate('Note')),
454            'FAM:SOUR:OBJE'            => new XrefMedia(I18N::translate('Media object')),
455            'FAM:SOUR:PAGE'            => new WhereWithinSource(I18N::translate('Citation details')),
456            'FAM:SOUR:QUAY'            => new CertaintyAssessment(I18N::translate('Quality of data')),
457            'FAM:SUBM'                 => new XrefSubmitter(I18N::translate('Submitter')),
458            'FAM:WIFE'                 => new XrefIndividual(I18N::translate('Wife')),
459            'HEAD'                     => new HeaderRecord(I18N::translate('Header')),
460            'HEAD:CHAR'                => new CharacterSet(I18N::translate('Character set')),
461            'HEAD:CHAR:VERS'           => new VersionNumber(I18N::translate('Version')),
462            'HEAD:COPR'                => new CopyrightFile(I18N::translate('Copyright')),
463            'HEAD:DATE'                => new TransmissionDate(I18N::translate('Date')),
464            'HEAD:DATE:TIME'           => new TimeValue(I18N::translate('Time')),
465            'HEAD:DEST'                => new ReceivingSystemName(I18N::translate('Destination')),
466            'HEAD:FILE'                => new FileName(I18N::translate('Filename')),
467            'HEAD:GEDC'                => new GedcomElement(I18N::translate('GEDCOM')),
468            'HEAD:GEDC:FORM'           => new Form(I18N::translate('Format')),
469            'HEAD:GEDC:VERS'           => new VersionNumber(I18N::translate('Version')),
470            'HEAD:LANG'                => new LanguageId(I18N::translate('Language')),
471            'HEAD:NOTE'                => new ContentDescription(I18N::translate('Note')),
472            'HEAD:PLAC'                => new EmptyElement(I18N::translate('Place hierarchy'), ['FORM' => '1:1']),
473            'HEAD:PLAC:FORM'           => new PlaceHierarchy(I18N::translate('Format')),
474            'HEAD:SOUR'                => new ApprovedSystemId('Genealogy software'),
475            'HEAD:SOUR:CORP'           => new NameOfBusiness(I18N::translate('Corporation')),
476            'HEAD:SOUR:CORP:ADDR'      => new AddressLine(I18N::translate('Address')),
477            'HEAD:SOUR:CORP:ADDR:ADR1' => new AddressLine1(I18N::translate('Address line 1')),
478            'HEAD:SOUR:CORP:ADDR:ADR2' => new AddressLine2(I18N::translate('Address line 2')),
479            'HEAD:SOUR:CORP:ADDR:ADR3' => new AddressLine3(I18N::translate('Address line 3')),
480            'HEAD:SOUR:CORP:ADDR:CITY' => new AddressCity(I18N::translate('City')),
481            'HEAD:SOUR:CORP:ADDR:CTRY' => new AddressCountry(I18N::translate('Country')),
482            'HEAD:SOUR:CORP:ADDR:POST' => new AddressPostalCode(I18N::translate('Postal code')),
483            'HEAD:SOUR:CORP:ADDR:STAE' => new AddressState(I18N::translate('State')),
484            'HEAD:SOUR:CORP:EMAIL'     => new AddressEmail(I18N::translate('Email address')),
485            'HEAD:SOUR:CORP:FAX'       => new AddressFax(I18N::translate('Fax')),
486            'HEAD:SOUR:CORP:PHON'      => new PhoneNumber(I18N::translate('Phone')),
487            'HEAD:SOUR:CORP:WWW'       => new AddressWebPage(I18N::translate('URL')),
488            'HEAD:SOUR:DATA'           => new NameOfSourceData('Data'),
489            'HEAD:SOUR:DATA:COPR'      => new CopyrightSourceData(I18N::translate('Copyright')),
490            'HEAD:SOUR:DATA:DATE'      => new PublicationDate(I18N::translate('Date')),
491            'HEAD:SOUR:NAME'           => new NameOfProduct('Software product'),
492            'HEAD:SOUR:VERS'           => new VersionNumber(I18N::translate('Version')),
493            'HEAD:SUBM'                => new XrefSubmitter(I18N::translate('Submitter')),
494            'HEAD:SUBN'                => new XrefSubmission(I18N::translate('Submission')),
495            'INDI'                     => new IndividualRecord(I18N::translate('Individual')),
496            'INDI:*:ADDR'              => new AddressLine(I18N::translate('Address')),
497            'INDI:*:ADDR:ADR1'         => new AddressLine1(I18N::translate('Address line 1')),
498            'INDI:*:ADDR:ADR2'         => new AddressLine2(I18N::translate('Address line 2')),
499            'INDI:*:ADDR:ADR3'         => new AddressLine3(I18N::translate('Address line 3')),
500            'INDI:*:ADDR:CITY'         => new AddressCity(I18N::translate('City')),
501            'INDI:*:ADDR:CTRY'         => new AddressCountry(I18N::translate('Country')),
502            'INDI:*:ADDR:POST'         => new AddressPostalCode(I18N::translate('Postal code')),
503            'INDI:*:ADDR:STAE'         => new AddressState(I18N::translate('State')),
504            'INDI:*:AGE'               => new AgeAtEvent(I18N::translate('Age')),
505            'INDI:*:AGNC'              => new ResponsibleAgency(I18N::translate('Agency')),
506            'INDI:*:CAUS'              => new CauseOfEvent(I18N::translate('Cause')),
507            'INDI:*:DATE'              => new DateValue(I18N::translate('Date')),
508            'INDI:*:EMAIL'             => new AddressEmail(I18N::translate('Email address')),
509            'INDI:*:FAX'               => new AddressFax(I18N::translate('Fax')),
510            'INDI:*:NOTE'              => new NoteStructure(I18N::translate('Note')),
511            'INDI:*:OBJE'              => new XrefMedia(I18N::translate('Media object')),
512            'INDI:*:PHON'              => new PhoneNumber(I18N::translate('Phone')),
513            'INDI:*:PLAC'              => new PlaceName(I18N::translate('Place')),
514            'INDI:*:PLAC:FONE'         => new PlacePhoneticVariation(I18N::translate('Phonetic place')),
515            'INDI:*:PLAC:FONE:TYPE'    => new PhoneticType(I18N::translate('Type')),
516            'INDI:*:PLAC:FORM'         => new PlaceHierarchy(I18N::translate('Format')),
517            'INDI:*:PLAC:MAP'          => new Coordinates(I18N::translate('Coordinates')),
518            'INDI:*:PLAC:MAP:LATI'     => new PlaceLatitude(I18N::translate('Latitude')),
519            'INDI:*:PLAC:MAP:LONG'     => new PlaceLongtitude(I18N::translate('Longitude')),
520            'INDI:*:PLAC:NOTE'         => new NoteStructure(I18N::translate('Note')),
521            'INDI:*:PLAC:ROMN'         => new PlaceRomanizedVariation(I18N::translate('Romanized place')),
522            'INDI:*:PLAC:ROMN:TYPE'    => new RomanizedType(I18N::translate('Type')),
523            'INDI:*:RELI'              => new ReligiousAffiliation(I18N::translate('Religion'), []),
524            'INDI:*:RESN'              => new RestrictionNotice(I18N::translate('Restriction')),
525            'INDI:*:SOUR'              => new XrefSource(I18N::translate('Source citation')),
526            'INDI:*:SOUR:DATA'         => new SourceData(I18N::translate('Data')),
527            'INDI:*:SOUR:DATA:DATE'    => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
528            'INDI:*:SOUR:DATA:TEXT'    => new TextFromSource(I18N::translate('Text')),
529            'INDI:*:SOUR:EVEN'         => new EventTypeCitedFrom(I18N::translate('Event')),
530            'INDI:*:SOUR:EVEN:ROLE'    => new RoleInEvent(I18N::translate('Role')),
531            'INDI:*:SOUR:NOTE'         => new NoteStructure(I18N::translate('Note')),
532            'INDI:*:SOUR:OBJE'         => new XrefMedia(I18N::translate('Media object')),
533            'INDI:*:SOUR:PAGE'         => new WhereWithinSource(I18N::translate('Citation details')),
534            'INDI:*:SOUR:QUAY'         => new CertaintyAssessment(I18N::translate('Quality of data')),
535            'INDI:*:TYPE'              => new EventOrFactClassification(I18N::translate('Type')),
536            'INDI:*:WWW'               => new AddressWebPage(I18N::translate('URL')),
537            'INDI:ADOP'                => new Adoption(I18N::translate('Adoption')),
538            'INDI:ADOP:DATE'           => new DateValue(I18N::translate('Date of adoption')),
539            'INDI:ADOP:FAMC'           => new XrefFamily(I18N::translate('Adoptive parents')),
540            'INDI:ADOP:FAMC:ADOP'      => new AdoptedByWhichParent(I18N::translate('Adoption')),
541            'INDI:ADOP:PLAC'           => new PlaceName(I18N::translate('Place of adoption')),
542            'INDI:AFN'                 => new AncestralFileNumber(I18N::translate('Ancestral file number')),
543            'INDI:ALIA'                => new XrefIndividual(I18N::translate('Alias')),
544            'INDI:ANCI'                => new XrefSubmitter(I18N::translate('Ancestors interest')),
545            'INDI:ASSO'                => new XrefAssociate(I18N::translate('Associate')),
546            'INDI:ASSO:RELA'           => new RelationIsDescriptor(I18N::translate('Relationship')),
547            'INDI:BAPL'                => new LdsBaptism(I18N::translate('LDS baptism')),
548            'INDI:BAPL:DATE'           => new DateLdsOrd(I18N::translate('Date of LDS baptism')),
549            'INDI:BAPL:PLAC'           => new PlaceLivingOrdinance(I18N::translate('Place of LDS baptism')),
550            'INDI:BAPL:STAT'           => new LdsBaptismDateStatus(I18N::translate('Status')),
551            'INDI:BAPL:STAT:DATE'      => new ChangeDate(I18N::translate('Status change date')),
552            'INDI:BAPL:TEMP'           => new TempleCode(I18N::translate('Temple')),
553            'INDI:BAPM'                => new Baptism(I18N::translate('Baptism')),
554            'INDI:BAPM:DATE'           => new DateValue(I18N::translate('Date of baptism')),
555            'INDI:BAPM:PLAC'           => new PlaceName(I18N::translate('Place of baptism')),
556            'INDI:BARM'                => new BarMitzvah(I18N::translate('Bar mitzvah')),
557            'INDI:BARM:DATE'           => new DateValue(I18N::translate('Date of bar mitzvah')),
558            'INDI:BARM:PLAC'           => new PlaceName(I18N::translate('Place of bar mitzvah')),
559            'INDI:BASM'                => new BasMitzvah(I18N::translate('Bat mitzvah')),
560            'INDI:BASM:DATE'           => new BasMitzvah(I18N::translate('Date of bat mitzvah')),
561            'INDI:BASM:PLAC'           => new DateValue(I18N::translate('Place of bat mitzvah')),
562            'INDI:BIRT'                => new Birth(I18N::translate('Birth')),
563            'INDI:BIRT:DATE'           => new DateValue(I18N::translate('Date of birth')),
564            'INDI:BIRT:FAMC'           => new XrefFamily(I18N::translate('Birth parents')),
565            'INDI:BIRT:PLAC'           => new PlaceName(I18N::translate('Place of birth')),
566            'INDI:BLES'                => new Blessing(I18N::translate('Blessing')),
567            'INDI:BLES:DATE'           => new DateValue(I18N::translate('Date of blessing')),
568            'INDI:BLES:PLAC'           => new PlaceName(I18N::translate('Place of blessing')),
569            'INDI:BURI'                => new Burial(I18N::translate('Burial')),
570            'INDI:BURI:DATE'           => new DateValue(I18N::translate('Date of burial')),
571            'INDI:BURI:PLAC'           => new PlaceName(I18N::translate('Place of burial')),
572            'INDI:CAST'                => new CasteName(I18N::translate('Caste')),
573            'INDI:CENS'                => new Census(I18N::translate('Census')),
574            'INDI:CENS:DATE'           => new DateValue(I18N::translate('Census date')),
575            'INDI:CENS:PLAC'           => new PlaceName(I18N::translate('Census place')),
576            'INDI:CHAN'                => new Change(I18N::translate('Last change')),
577            'INDI:CHAN:DATE'           => new ChangeDate(I18N::translate('Date of last change')),
578            'INDI:CHAN:DATE:TIME'      => new TimeValue(I18N::translate('Time of last change')),
579            'INDI:CHR'                 => new Christening(I18N::translate('Christening')),
580            'INDI:CHR:DATE'            => new DateValue(I18N::translate('Date of christening')),
581            'INDI:CHR:FAMC'            => new XrefFamily(I18N::translate('Godparents')),
582            'INDI:CHR:PLAC'            => new PlaceName(I18N::translate('Place of christening')),
583            'INDI:CHRA'                => new AdultChristening(I18N::translate('Adult christening')),
584            'INDI:CHRA:PLAC'           => new PlaceName(I18N::translate('Place of christening')),
585            'INDI:CONF'                => new Confirmation(I18N::translate('Confirmation')),
586            'INDI:CONF:DATE'           => new DateValue(I18N::translate('Date of confirmation')),
587            'INDI:CONF:PLAC'           => new PlaceName(I18N::translate('Place of confirmation')),
588            'INDI:CONL'                => new LdsConfirmation(I18N::translate('LDS confirmation')),
589            'INDI:CONL:DATE'           => new DateLdsOrd(I18N::translate('Date of LDS confirmation')),
590            'INDI:CONL:PLAC'           => new PlaceLivingOrdinance(I18N::translate('Place of LDS confirmation')),
591            'INDI:CONL:STAT'           => new LdsSpouseSealingDateStatus(I18N::translate('Status')),
592            'INDI:CONL:STAT:DATE'      => new ChangeDate(I18N::translate('Status change date')),
593            'INDI:CONL:TEMP'           => new TempleCode(I18N::translate('Temple')),
594            'INDI:CREM'                => new Cremation(I18N::translate('Cremation')),
595            'INDI:CREM:DATE'           => new DateValue(I18N::translate('Date of cremation')),
596            'INDI:CREM:PLAC'           => new PlaceName(I18N::translate('Place of cremation')),
597            'INDI:DEAT'                => new Death(I18N::translate('Death')),
598            'INDI:DEAT:CAUS'           => new CauseOfEvent(I18N::translate('Cause of death')),
599            'INDI:DEAT:DATE'           => new DateValue(I18N::translate('Date of death')),
600            'INDI:DEAT:PLAC'           => new PlaceName(I18N::translate('Place of death')),
601            'INDI:DESI'                => new XrefSubmitter(I18N::translate('Descendants interest')),
602            'INDI:DSCR'                => new PhysicalDescription(I18N::translate('Description')),
603            'INDI:EDUC'                => new ScholasticAchievement(I18N::translate('Education')),
604            'INDI:EDUC:AGNC'           => new ResponsibleAgency(I18N::translate('School or college')),
605            'INDI:EMIG'                => new Emigration(I18N::translate('Emigration')),
606            'INDI:EMIG:DATE'           => new DateValue(I18N::translate('Date of emigration')),
607            'INDI:EMIG:PLAC'           => new PlaceName(I18N::translate('Place of emigration')),
608            'INDI:ENDL'                => new LdsEndowment(I18N::translate('LDS endowment')),
609            'INDI:ENDL:DATE'           => new DateLdsOrd(I18N::translate('Date of LDS endowment')),
610            'INDI:ENDL:PLAC'           => new PlaceLivingOrdinance(I18N::translate('Place of LDS endowment')),
611            'INDI:ENDL:STAT'           => new LdsEndowmentDateStatus(I18N::translate('Status')),
612            'INDI:ENDL:STAT:DATE'      => new ChangeDate(I18N::translate('Status change date')),
613            'INDI:ENDL:TEMP'           => new TempleCode(I18N::translate('Temple')),
614            'INDI:EVEN'                => new CustomIndividualEvent(I18N::translate('Event')),
615            'INDI:EVEN:DATE'           => new DateValue(I18N::translate('Date of event')),
616            'INDI:EVEN:PLAC'           => new PlaceName(I18N::translate('Place of event')),
617            'INDI:EVEN:TYPE'           => new EventAttributeType(I18N::translate('Type of event')),
618            'INDI:FACT'                => new CustomFact(I18N::translate('Fact')),
619            'INDI:FACT:TYPE'           => new EventAttributeType(I18N::translate('Type of fact')),
620            'INDI:FAMC'                => new XrefFamily(I18N::translate('Family as a child'), ['NOTE' => '0:1', 'PEDI' => '0:1', 'STAT' => '0:1']),
621            'INDI:FAMC:PEDI'           => new PedigreeLinkageType(I18N::translate('Relationship to parents')),
622            'INDI:FAMC:STAT'           => new ChildLinkageStatus(I18N::translate('Status')),
623            'INDI:FAMS'                => new XrefFamily(I18N::translate('Family as a spouse')),
624            'INDI:FCOM'                => new FirstCommunion(I18N::translate('First communion')),
625            'INDI:FCOM:DATE'           => new DateValue(I18N::translate('Date of first communion')),
626            'INDI:FCOM:PLAC'           => new PlaceName(I18N::translate('Place of first communion')),
627            'INDI:GRAD'                => new Graduation(I18N::translate('Graduation')),
628            'INDI:GRAD:AGNC'           => new ResponsibleAgency(I18N::translate('School or college')),
629            'INDI:IDNO'                => new NationalIdNumber(I18N::translate('Identification number')),
630            'INDI:IDNO:TYPE'           => new EventAttributeType(I18N::translate('Type of identification number')),
631            'INDI:IMMI'                => new Immigration(I18N::translate('Immigration')),
632            'INDI:IMMI:DATE'           => new DateValue(I18N::translate('Date of immigration')),
633            'INDI:IMMI:PLAC'           => new PlaceName(I18N::translate('Place of immigration')),
634            'INDI:NAME'                => new NamePersonal(I18N::translate('Name')),
635            'INDI:NAME:FONE'           => new NamePhoneticVariation(I18N::translate('Phonetic name')),
636            'INDI:NAME:FONE:GIVN'      => new NamePieceGiven(I18N::translate('Given names')),
637            'INDI:NAME:FONE:NICK'      => new NamePieceNickname(I18N::translate('Nickname')),
638            'INDI:NAME:FONE:NPFX'      => new NamePiecePrefix(I18N::translate('Name prefix')),
639            'INDI:NAME:FONE:NSFX'      => new NamePieceSuffix(I18N::translate('Name suffix')),
640            'INDI:NAME:FONE:SPFX'      => new NamePieceSurnamePrefix(I18N::translate('Surname prefix')),
641            'INDI:NAME:FONE:SURN'      => new NamePieceSurname(I18N::translate('Surname')),
642            'INDI:NAME:FONE:TYPE'      => new PhoneticType(I18N::translate('Phonetic type')),
643            'INDI:NAME:GIVN'           => new NamePieceGiven(I18N::translate('Given names')),
644            'INDI:NAME:NICK'           => new NamePieceNickname(I18N::translate('Nickname')),
645            'INDI:NAME:NPFX'           => new NamePiecePrefix(I18N::translate('Name prefix')),
646            'INDI:NAME:NSFX'           => new NamePieceSuffix(I18N::translate('Name suffix')),
647            'INDI:NAME:ROMN'           => new NameRomanizedVariation(I18N::translate('Romanized name')),
648            'INDI:NAME:ROMN:GIVN'      => new NamePieceGiven(I18N::translate('Given names')),
649            'INDI:NAME:ROMN:NICK'      => new NamePieceNickname(I18N::translate('Nickname')),
650            'INDI:NAME:ROMN:NPFX'      => new NamePiecePrefix(I18N::translate('Name prefix')),
651            'INDI:NAME:ROMN:NSFX'      => new NamePieceSuffix(I18N::translate('Name suffix')),
652            'INDI:NAME:ROMN:SPFX'      => new NamePieceSurnamePrefix(I18N::translate('Surname prefix')),
653            'INDI:NAME:ROMN:SURN'      => new NamePieceSurname(I18N::translate('Surname')),
654            'INDI:NAME:ROMN:TYPE'      => new RomanizedType(I18N::translate('Romanized type')),
655            'INDI:NAME:SPFX'           => new NamePieceSurnamePrefix(I18N::translate('Surname prefix')),
656            'INDI:NAME:SURN'           => new NamePieceSurname(I18N::translate('Surname')),
657            'INDI:NAME:TYPE'           => new NameType(I18N::translate('Type of name')),
658            'INDI:NATI'                => new NationOrTribalOrigin(I18N::translate('Nationality')),
659            'INDI:NATU'                => new Naturalization(I18N::translate('Naturalization')),
660            'INDI:NATU:DATE'           => new DateValue(I18N::translate('Date of naturalization')),
661            'INDI:NATU:PLAC'           => new PlaceName(I18N::translate('Place of naturalization')),
662            'INDI:NCHI'                => new CountOfChildren(I18N::translate('Number of children')),
663            'INDI:NMR'                 => new CountOfMarriages(I18N::translate('Number of marriages')),
664            'INDI:NOTE'                => new NoteStructure(I18N::translate('Note')),
665            'INDI:OBJE'                => new XrefMedia(I18N::translate('Media object')),
666            'INDI:OCCU'                => new Occupation(I18N::translate('Occupation')),
667            'INDI:OCCU:AGNC'           => new ResponsibleAgency(I18N::translate('Employer')),
668            'INDI:ORDN'                => new Ordination(I18N::translate('Ordination')),
669            'INDI:ORDN:AGNC'           => new Ordination(I18N::translate('Religious institution')),
670            'INDI:ORDN:DATE'           => new Ordination(I18N::translate('Date of ordination')),
671            'INDI:ORDN:PLAC'           => new Ordination(I18N::translate('Place of ordination')),
672            'INDI:PROB'                => new Probate(I18N::translate('Probate')),
673            'INDI:PROP'                => new Possessions(I18N::translate('Property')),
674            'INDI:REFN'                => new UserReferenceNumber(I18N::translate('Reference number')),
675            'INDI:REFN:TYPE'           => new UserReferenceType(I18N::translate('Type of reference number')),
676            'INDI:RELI'                => new ReligiousAffiliation(I18N::translate('Religion')),
677            'INDI:RESI'                => new Residence(I18N::translate('Residence')),
678            'INDI:RESI:DATE'           => new DateValue(I18N::translate('Date of residence')),
679            'INDI:RESI:PLAC'           => new PlaceName(I18N::translate('Place of residence')),
680            'INDI:RESN'                => new RestrictionNotice(I18N::translate('Restriction')),
681            'INDI:RETI'                => new Retirement(I18N::translate('Retirement')),
682            'INDI:RETI:AGNC'           => new ResponsibleAgency(I18N::translate('Employer')),
683            'INDI:RFN'                 => new PermanentRecordFileNumber(I18N::translate('Record file number')),
684            'INDI:RIN'                 => new AutomatedRecordId(I18N::translate('Record ID number')),
685            'INDI:SEX'                 => new SexValue(I18N::translate('Gender')),
686            'INDI:SLGC'                => new LdsChildSealing(I18N::translate('LDS child sealing')),
687            'INDI:SLGC:DATE'           => new DateLdsOrd(I18N::translate('Date of LDS child sealing')),
688            'INDI:SLGC:FAMC'           => new XrefFamily(I18N::translate('Parents')),
689            'INDI:SLGC:PLAC'           => new PlaceLivingOrdinance(I18N::translate('Place of LDS child sealing')),
690            'INDI:SLGC:STAT'           => new LdsChildSealingDateStatus(I18N::translate('Status')),
691            'INDI:SLGC:STAT:DATE'      => new ChangeDate(I18N::translate('Status change date')),
692            'INDI:SLGC:TEMP'           => new TempleCode(I18N::translate('Temple')),
693            'INDI:SOUR'                => new XrefSource(I18N::translate('Source citation')),
694            'INDI:SOUR:DATA'           => new SourceData(I18N::translate('Data')),
695            'INDI:SOUR:DATA:DATE'      => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
696            'INDI:SOUR:DATA:TEXT'      => new TextFromSource(I18N::translate('Text')),
697            'INDI:SOUR:EVEN'           => new EventTypeCitedFrom(I18N::translate('Event')),
698            'INDI:SOUR:EVEN:ROLE'      => new RoleInEvent(I18N::translate('Role')),
699            'INDI:SOUR:NOTE'           => new NoteStructure(I18N::translate('Note')),
700            'INDI:SOUR:OBJE'           => new XrefMedia(I18N::translate('Media object')),
701            'INDI:SOUR:PAGE'           => new WhereWithinSource(I18N::translate('Citation details')),
702            'INDI:SOUR:QUAY'           => new CertaintyAssessment(I18N::translate('Quality of data')),
703            'INDI:SSN'                 => new SocialSecurityNumber(I18N::translate('Social security number')),
704            'INDI:SUBM'                => new XrefSubmitter(I18N::translate('Submitter')),
705            'INDI:TITL'                => new NobilityTypeTitle(I18N::translate('Title')),
706            'INDI:WILL'                => new Will(I18N::translate('Will')),
707            'NOTE'                     => new NoteRecord(I18N::translate('Shared note')),
708            'NOTE:CHAN'                => new Change(I18N::translate('Last change')),
709            'NOTE:CHAN:DATE'           => new ChangeDate(I18N::translate('Date of last change')),
710            'NOTE:CHAN:DATE:TIME'      => new TimeValue(I18N::translate('Time of last change')),
711            'NOTE:CHAN:NOTE'           => new NoteStructure(I18N::translate('Note')),
712            'NOTE:CONC'                => new SubmitterText(I18N::translate('Note')),
713            'NOTE:REFN'                => new UserReferenceNumber(I18N::translate('Reference number')),
714            'NOTE:REFN:TYPE'           => new UserReferenceType(I18N::translate('Type of reference number')),
715            'NOTE:RIN'                 => new AutomatedRecordId(I18N::translate('Record ID number')),
716            'NOTE:SOUR'                => new XrefSource(I18N::translate('Source citation')),
717            'NOTE:SOUR:DATA'           => new SourceData(I18N::translate('Data')),
718            'NOTE:SOUR:DATA:DATE'      => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
719            'NOTE:SOUR:DATA:TEXT'      => new TextFromSource(I18N::translate('Text')),
720            'NOTE:SOUR:EVEN'           => new EventTypeCitedFrom(I18N::translate('Event')),
721            'NOTE:SOUR:EVEN:ROLE'      => new RoleInEvent(I18N::translate('Role')),
722            'NOTE:SOUR:NOTE'           => new NoteStructure(I18N::translate('Note')),
723            'NOTE:SOUR:OBJE'           => new XrefMedia(I18N::translate('Media object')),
724            'NOTE:SOUR:PAGE'           => new WhereWithinSource(I18N::translate('Citation details')),
725            'NOTE:SOUR:QUAY'           => new CertaintyAssessment(I18N::translate('Quality of data')),
726            'OBJE'                     => new MediaRecord(I18N::translate('Media object')),
727            'OBJE:BLOB'                => new CustomElement(I18N::translate('Binary data object')),
728            'OBJE:CHAN'                => new Change(I18N::translate('Last change')),
729            'OBJE:CHAN:DATE'           => new ChangeDate(I18N::translate('Date of last change')),
730            'OBJE:CHAN:DATE:TIME'      => new TimeValue(I18N::translate('Time of last change')),
731            'OBJE:CHAN:NOTE'           => new NoteStructure(I18N::translate('Note')),
732            'OBJE:FILE'                => new MultimediaFileReference(I18N::translate('Filename')),
733            'OBJE:FILE:FORM'           => new MultimediaFormat(I18N::translate('Format')),
734            'OBJE:FILE:FORM:TYPE'      => new SourceMediaType(I18N::translate('Media type')),
735            'OBJE:FILE:TITL'           => new DescriptiveTitle(I18N::translate('Title')),
736            'OBJE:NOTE'                => new NoteStructure(I18N::translate('Note')),
737            'OBJE:REFN'                => new UserReferenceNumber(I18N::translate('Reference number')),
738            'OBJE:REFN:TYPE'           => new UserReferenceType(I18N::translate('Type of reference number')),
739            'OBJE:RIN'                 => new AutomatedRecordId(I18N::translate('Record ID number')),
740            'OBJE:SOUR'                => new XrefSource(I18N::translate('Source citation')),
741            'OBJE:SOUR:DATA'           => new SourceData(I18N::translate('Data')),
742            'OBJE:SOUR:DATA:DATE'      => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
743            'OBJE:SOUR:DATA:TEXT'      => new TextFromSource(I18N::translate('Text')),
744            'OBJE:SOUR:EVEN'           => new EventTypeCitedFrom(I18N::translate('Event')),
745            'OBJE:SOUR:EVEN:ROLE'      => new RoleInEvent(I18N::translate('Role')),
746            'OBJE:SOUR:NOTE'           => new NoteStructure(I18N::translate('Note')),
747            'OBJE:SOUR:OBJE'           => new XrefMedia(I18N::translate('Media object')),
748            'OBJE:SOUR:PAGE'           => new WhereWithinSource(I18N::translate('Citation details')),
749            'OBJE:SOUR:QUAY'           => new CertaintyAssessment(I18N::translate('Quality of data')),
750            'REPO'                     => new RepositoryRecord(I18N::translate('Repository')),
751            'REPO:ADDR'                => new AddressLine(I18N::translate('Address')),
752            'REPO:ADDR:ADR1'           => new AddressLine1(I18N::translate('Address line 1')),
753            'REPO:ADDR:ADR2'           => new AddressLine2(I18N::translate('Address line 2')),
754            'REPO:ADDR:ADR3'           => new AddressLine3(I18N::translate('Address line 3')),
755            'REPO:ADDR:CITY'           => new AddressCity(I18N::translate('City')),
756            'REPO:ADDR:CTRY'           => new AddressCountry(I18N::translate('Country')),
757            'REPO:ADDR:POST'           => new AddressPostalCode(I18N::translate('Postal code')),
758            'REPO:ADDR:STAE'           => new AddressState(I18N::translate('State')),
759            'REPO:CHAN'                => new Change(I18N::translate('Last change')),
760            'REPO:CHAN:DATE'           => new ChangeDate(I18N::translate('Date of last change')),
761            'REPO:CHAN:DATE:TIME'      => new TimeValue(I18N::translate('Time of last change')),
762            'REPO:CHAN:NOTE'           => new NoteStructure(I18N::translate('Note')),
763            'REPO:EMAIL'               => new AddressEmail(I18N::translate('Email address')),
764            'REPO:FAX'                 => new AddressFax(I18N::translate('Fax')),
765            'REPO:NAME'                => new NameOfRepository(I18N::translateContext('Repository', 'Name')),
766            'REPO:NOTE'                => new NoteStructure(I18N::translate('Note')),
767            'REPO:PHON'                => new PhoneNumber(I18N::translate('Phone')),
768            'REPO:REFN'                => new UserReferenceNumber(I18N::translate('Reference number')),
769            'REPO:REFN:TYPE'           => new UserReferenceType(I18N::translate('Type of reference number')),
770            'REPO:RIN'                 => new AutomatedRecordId(I18N::translate('Record ID number')),
771            'REPO:WWW'                 => new AddressWebPage(I18N::translate('URL')),
772            'SOUR'                     => new SourceRecord(I18N::translate('Source')),
773            'SOUR:ABBR'                => new SourceFiledByEntry(I18N::translate('Abbreviation')),
774            'SOUR:AUTH'                => new SourceOriginator(I18N::translate('Author')),
775            'SOUR:CHAN'                => new Change(I18N::translate('Last change')),
776            'SOUR:CHAN:DATE'           => new ChangeDate(I18N::translate('Date of last change')),
777            'SOUR:CHAN:DATE:TIME'      => new TimeValue(I18N::translate('Time of last change')),
778            'SOUR:CHAN:NOTE'           => new NoteStructure(I18N::translate('Note')),
779            'SOUR:DATA'                => new EmptyElement(I18N::translate('Data'), ['EVEN' => '0:M', 'AGNC' => '0:1', 'NOTE' => '0:M']),
780            'SOUR:DATA:AGNC'           => new ResponsibleAgency(I18N::translate('Agency')),
781            'SOUR:DATA:EVEN'           => new EventsRecorded(I18N::translate('Events')),
782            'SOUR:DATA:EVEN:DATE'      => new DateValue(I18N::translate('Date range')),
783            'SOUR:DATA:EVEN:PLAC'      => new SourceJurisdictionPlace(I18N::translate('Place'), []),
784            'SOUR:DATA:NOTE'           => new NoteStructure(I18N::translate('Note')),
785            'SOUR:NOTE'                => new NoteStructure(I18N::translate('Note')),
786            'SOUR:OBJE'                => new XrefMedia(I18N::translate('Media object')),
787            'SOUR:PUBL'                => new SourcePublicationFacts(I18N::translate('Publication')),
788            'SOUR:REFN'                => new UserReferenceNumber(I18N::translate('Reference number')),
789            'SOUR:REFN:TYPE'           => new UserReferenceType(I18N::translate('Type of reference number')),
790            'SOUR:REPO'                => new XrefRepository(I18N::translate('Repository')),
791            'SOUR:REPO:CALN'           => new SourceCallNumber(I18N::translate('Call number')),
792            'SOUR:REPO:CALN:MEDI'      => new SourceMediaType(I18N::translate('Media type')),
793            'SOUR:REPO:NOTE'           => new NoteStructure(I18N::translate('Note')),
794            'SOUR:RIN'                 => new AutomatedRecordId(I18N::translate('Record ID number')),
795            'SOUR:TEXT'                => new TextFromSource(I18N::translate('Text')),
796            'SOUR:TITL'                => new DescriptiveTitle(I18N::translate('Title')),
797            'SUBM'                     => new SubmitterRecord(I18N::translate('Submitter')),
798            'SUBM:ADDR'                => new AddressLine(I18N::translate('Address')),
799            'SUBM:ADDR:ADR1'           => new AddressLine1(I18N::translate('Address line 1')),
800            'SUBM:ADDR:ADR2'           => new AddressLine2(I18N::translate('Address line 2')),
801            'SUBM:ADDR:ADR3'           => new AddressLine3(I18N::translate('Address line 3')),
802            'SUBM:ADDR:CITY'           => new AddressCity(I18N::translate('City')),
803            'SUBM:ADDR:CTRY'           => new AddressCountry(I18N::translate('Country')),
804            'SUBM:ADDR:POST'           => new AddressPostalCode(I18N::translate('Postal code')),
805            'SUBM:ADDR:STAE'           => new AddressState(I18N::translate('State')),
806            'SUBM:CHAN'                => new Change(I18N::translate('Last change')),
807            'SUBM:CHAN:DATE'           => new ChangeDate(I18N::translate('Date of last change')),
808            'SUBM:CHAN:DATE:TIME'      => new TimeValue(I18N::translate('Time of last change')),
809            'SUBM:CHAN:NOTE'           => new NoteStructure(I18N::translate('Note')),
810            'SUBM:EMAIL'               => new AddressEmail(I18N::translate('Email address')),
811            'SUBM:FAX'                 => new AddressFax(I18N::translate('Fax')),
812            'SUBM:LANG'                => new LanguageId(I18N::translate('Language')),
813            'SUBM:NAME'                => new SubmitterName(I18N::translate('Name')),
814            'SUBM:NOTE'                => new NoteStructure(I18N::translate('Note')),
815            'SUBM:OBJE'                => new XrefMedia(I18N::translate('Media object')),
816            'SUBM:PHON'                => new PhoneNumber(I18N::translate('Phone')),
817            'SUBM:RFN'                 => new SubmitterRegisteredRfn(I18N::translate('Record file number')),
818            'SUBM:RIN'                 => new AutomatedRecordId(I18N::translate('Record ID number')),
819            'SUBM:WWW'                 => new AddressWebPage(I18N::translate('URL')),
820            'SUBN'                     => new SubmissionRecord(I18N::translate('Submission')),
821            'SUBN:ANCE'                => new GenerationsOfAncestors(I18N::translate('Generations of ancestors')),
822            'SUBN:CHAN'                => new Change(I18N::translate('Last change')),
823            'SUBN:CHAN:DATE'           => new ChangeDate(I18N::translate('Date of last change')),
824            'SUBN:CHAN:DATE:TIME'      => new TimeValue(I18N::translate('Time of last change')),
825            'SUBN:CHAN:NOTE'           => new NoteStructure(I18N::translate('Note')),
826            'SUBN:DESC'                => new GenerationsOfDescendants(I18N::translate('Generations of descendants')),
827            'SUBN:FAMF'                => new NameOfFamilyFile(I18N::translate('Family file')),
828            'SUBN:NOTE'                => new NoteStructure(I18N::translate('Note')),
829            'SUBN:ORDI'                => new OrdinanceProcessFlag(I18N::translate('Ordinance')),
830            'SUBN:RIN'                 => new AutomatedRecordId(I18N::translate('Record ID number')),
831            'SUBN:SUBM'                => new XrefSubmitter(I18N::translate('Submitter')),
832            'SUBN:TEMP'                => new TempleCode(/* I18N: https://en.wikipedia.org/wiki/Temple_(LDS_Church)*/ I18N::translate('Temple')),
833            'TRLR'                     => new EmptyElement(I18N::translate('Trailer')),
834        ];
835    }
836
837    /**
838     * @return array<string,ElementInterface>
839     */
840    private function ancestryTags(): array
841    {
842        return [
843            'INDI:*:SOUR:_APID' => new CustomElement(I18N::translate('Ancestry PID')),
844            'INDI:_EMPLOY'      => new CustomFact(I18N::translate('Occupation')),
845        ];
846    }
847
848    /**
849     * @return array<string,ElementInterface>
850     *
851     * @see https://wiki-de.genealogy.net/GEDCOM/_Nutzerdef-Tag
852     */
853    private function brothersKeeperTags(): array
854    {
855        return [
856            'FAM:*:_EVN'       => new CustomElement('Event number'),
857            'FAM:CHIL:_FREL'   => new CustomElement('Relationship to father'),
858            'FAM:CHIL:_MREL'   => new CustomElement('Relationship to mother'),
859            'FAM:_COML'        => new CustomFamilyEvent(I18N::translate('Common law marriage')),
860            'FAM:_MARI'        => new CustomFamilyEvent(I18N::translate('Marriage intention')),
861            'FAM:_MBON'        => new CustomFamilyEvent(I18N::translate('Marriage bond')),
862            'FAM:_NMR'         => new CustomFamilyEvent(I18N::translate('Not married'), ['NOTE' => '0:M', 'SOUR' => '0:M']),
863            'FAM:_PRMN'        => new CustomElement(I18N::translate('Permanent number')),
864            'FAM:_SEPR'        => new CustomFamilyEvent(I18N::translate('Separated')),
865            'FAM:_TODO'        => new CustomElement(I18N::translate('Research task')),
866            'INDI:*:_EVN'      => new CustomElement('Event number'),
867            'INDI:NAME:_ADPN'  => new NamePersonal(I18N::translate('Adopted name'), []),
868            'INDI:NAME:_AKAN'  => new NamePersonal(I18N::translate('Also known as'), []),
869            'INDI:NAME:_BIRN'  => new NamePersonal(I18N::translate('Birth name'), []),
870            'INDI:NAME:_CALL'  => new NamePersonal('Called name', []),
871            'INDI:NAME:_CENN'  => new NamePersonal('Census name', []),
872            'INDI:NAME:_CURN'  => new NamePersonal('Current name', []),
873            'INDI:NAME:_FARN'  => new NamePersonal(I18N::translate('Estate name'), []),
874            'INDI:NAME:_FKAN'  => new NamePersonal('Formal name', []),
875            'INDI:NAME:_FRKA'  => new NamePersonal('Formerly known as', []),
876            'INDI:NAME:_GERN'  => new NamePersonal('German name', []),
877            'INDI:NAME:_HEBN'  => new NamePersonal(I18N::translate('Hebrew name'), []),
878            'INDI:NAME:_HNM'   => new NamePersonal(I18N::translate('Hebrew name'), []),
879            'INDI:NAME:_INDG'  => new NamePersonal('Indigenous name', []),
880            'INDI:NAME:_INDN'  => new NamePersonal('Indian name', []),
881            'INDI:NAME:_LNCH'  => new NamePersonal('Legal name change', []),
882            'INDI:NAME:_MARN'  => new NamePersonal('Married name', []),
883            'INDI:NAME:_MARNM' => new NamePersonal('Married name', []),
884            'INDI:NAME:_OTHN'  => new NamePersonal('Other name', []),
885            'INDI:NAME:_RELN'  => new NamePersonal('Religious name', []),
886            'INDI:NAME:_SHON'  => new NamePersonal('Short name', []),
887            'INDI:NAME:_SLDN'  => new NamePersonal('Soldier name', []),
888            'INDI:_ADPF'       => new CustomElement(I18N::translate('Adopted by father')),
889            'INDI:_ADPM'       => new CustomElement(I18N::translate('Adopted by mother')),
890            'INDI:_BRTM'       => new CustomIndividualEvent(I18N::translate('Brit milah')),
891            'INDI:_BRTM:DATE'  => new DateValue(I18N::translate('Date of brit milah')),
892            'INDI:_BRTM:PLAC'  => new PlaceName(I18N::translate('Place of brit milah')),
893            'INDI:_EMAIL'      => new AddressEmail(I18N::translate('Email address')),
894            'INDI:_EYEC'       => new CustomFact(I18N::translate('Eye color')),
895            'INDI:_FRNL'       => new CustomElement(I18N::translate('Funeral')),
896            'INDI:_HAIR'       => new CustomFact(I18N::translate('Hair color')),
897            'INDI:_HEIG'       => new CustomFact(I18N::translate('Height')),
898            'INDI:_INTE'       => new CustomElement(I18N::translate('Interment')),
899            'INDI:_MEDC'       => new CustomFact(I18N::translate('Medical')),
900            'INDI:_MILT'       => new CustomElement(I18N::translate('Military service')),
901            'INDI:_NLIV'       => new CustomFact(I18N::translate('Not living')),
902            'INDI:_NMAR'       => new CustomFact(I18N::translate('Never married'), ['NOTE' => '0:M', 'SOUR' => '0:M']),
903            'INDI:_PRMN'       => new CustomElement(I18N::translate('Permanent number')),
904            'INDI:_TODO'       => new CustomElement(I18N::translate('Research task')),
905            'INDI:_WEIG'       => new CustomFact(I18N::translate('Weight')),
906            'INDI:_YART'       => new CustomIndividualEvent(I18N::translate('Yahrzeit')),
907            // 1 XXXX
908            // 2 _EVN ##
909            // 1 ASSO @Xnnn@
910            // 2 RELA Witness at event _EVN ##
911        ];
912    }
913
914    /**
915     * @return array<string,ElementInterface>
916     */
917    private function familySearchTags(): array
918    {
919        return [
920            'INDI:_FSFTID' => /* I18N: familysearch.org */ new FamilySearchFamilyTreeId(I18N::translate('FamilySearch ID')),
921        ];
922    }
923
924    /**
925     * @return array<string,ElementInterface>
926     */
927    private function familyTreeBuilderTags(): array
928    {
929        return [
930            '*:_UPD'              => new CustomElement(I18N::translate('Last change')), // e.g. "1 _UPD 14 APR 2012 00:14:10 GMT-5"
931            'INDI:NAME:_AKA'      => new NamePersonal(I18N::translate('Also known as'), []),
932            'OBJE:_ALBUM'         => new CustomElement(I18N::translate('Album')), // XREF to an album
933            'OBJE:_DATE'          => new DateValue(I18N::translate('Date')),
934            'OBJE:_FILESIZE'      => new CustomElement(I18N::translate('File size')),
935            'OBJE:_PHOTO_RIN'     => new CustomElement(I18N::translate('Record ID number')),
936            'OBJE:_PLACE'         => new PlaceName(I18N::translate('Place')),
937            '_ALBUM:_PHOTO'       => new CustomElement(I18N::translate('Photo')),
938            '_ALBUM:_PHOTO:_PRIN' => new CustomElement(I18N::translate('Highlighted image')),
939        ];
940    }
941
942    /**
943     * @return array<string,ElementInterface>
944     *
945     * @see https://wiki-de.genealogy.net/GEDCOM/_Nutzerdef-Tag
946     */
947    private function familyTreeMakerTags(): array
948    {
949        return [
950            'FAM:CHIL:_FREL'              => new CustomElement(I18N::translate('Relationship to father')),
951            'FAM:CHIL:_MREL'              => new CustomElement(I18N::translate('Relationship to mother')),
952            'FAM:_DETS'                   => new CustomElement(I18N::translate('Death of one spouse')),
953            'FAM:_FA1'                    => new CustomElement(I18N::translate('Fact 1')),
954            'FAM:_FA10'                   => new CustomElement(I18N::translate('Fact 10')),
955            'FAM:_FA11'                   => new CustomElement(I18N::translate('Fact 11')),
956            'FAM:_FA12'                   => new CustomElement(I18N::translate('Fact 12')),
957            'FAM:_FA13'                   => new CustomElement(I18N::translate('Fact 13')),
958            'FAM:_FA2'                    => new CustomElement(I18N::translate('Fact 2')),
959            'FAM:_FA3'                    => new CustomElement(I18N::translate('Fact 3')),
960            'FAM:_FA4'                    => new CustomElement(I18N::translate('Fact 4')),
961            'FAM:_FA5'                    => new CustomElement(I18N::translate('Fact 5')),
962            'FAM:_FA6'                    => new CustomElement(I18N::translate('Fact 6')),
963            'FAM:_FA7'                    => new CustomElement(I18N::translate('Fact 7')),
964            'FAM:_FA8'                    => new CustomElement(I18N::translate('Fact 8')),
965            'FAM:_FA9'                    => new CustomElement(I18N::translate('Fact 9')),
966            'FAM:_MEND'                   => new CustomElement(I18N::translate('Marriage ending status')),
967            'FAM:_MSTAT'                  => new CustomElement(I18N::translate('Marriage beginning status')),
968            'FAM:_SEPR'                   => new CustomElement(I18N::translate('Separation')),
969            'HEAD:_SCHEMA'                => new CustomElement('Schema'),
970            'HEAD:_SCHEMA:FAM'            => new CustomElement(I18N::translate('Family')),
971            'HEAD:_SCHEMA:FAM:_FA*:LABL'  => new CustomElement(I18N::translate('Label')),
972            'HEAD:_SCHEMA:FAM:_FA1'       => new CustomElement(I18N::translate('Fact 1')),
973            'HEAD:_SCHEMA:FAM:_FA10'      => new CustomElement(I18N::translate('Fact 10')),
974            'HEAD:_SCHEMA:FAM:_FA11'      => new CustomElement(I18N::translate('Fact 11')),
975            'HEAD:_SCHEMA:FAM:_FA12'      => new CustomElement(I18N::translate('Fact 12')),
976            'HEAD:_SCHEMA:FAM:_FA13'      => new CustomElement(I18N::translate('Fact 13')),
977            'HEAD:_SCHEMA:FAM:_FA2'       => new CustomElement(I18N::translate('Fact 2')),
978            'HEAD:_SCHEMA:FAM:_FA3'       => new CustomElement(I18N::translate('Fact 3')),
979            'HEAD:_SCHEMA:FAM:_FA4'       => new CustomElement(I18N::translate('Fact 4')),
980            'HEAD:_SCHEMA:FAM:_FA5'       => new CustomElement(I18N::translate('Fact 5')),
981            'HEAD:_SCHEMA:FAM:_FA6'       => new CustomElement(I18N::translate('Fact 6')),
982            'HEAD:_SCHEMA:FAM:_FA7'       => new CustomElement(I18N::translate('Fact 7')),
983            'HEAD:_SCHEMA:FAM:_FA8'       => new CustomElement(I18N::translate('Fact 8')),
984            'HEAD:_SCHEMA:FAM:_FA9'       => new CustomElement(I18N::translate('Fact 9')),
985            'HEAD:_SCHEMA:FAM:_M*:LABL'   => new CustomElement(I18N::translate('Label')),
986            'HEAD:_SCHEMA:FAM:_MEND'      => new CustomElement(I18N::translate('Marriage ending status')),
987            'HEAD:_SCHEMA:FAM:_MSTAT'     => new CustomElement(I18N::translate('Marriage beginning status')),
988            'HEAD:_SCHEMA:INDI'           => new CustomElement(I18N::translate('Individual')),
989            'HEAD:_SCHEMA:INDI:_FA*:LABL' => new CustomElement(I18N::translate('Label')),
990            'HEAD:_SCHEMA:INDI:_FA1'      => new CustomElement(I18N::translate('Fact 1')),
991            'HEAD:_SCHEMA:INDI:_FA10'     => new CustomElement(I18N::translate('Fact 10')),
992            'HEAD:_SCHEMA:INDI:_FA11'     => new CustomElement(I18N::translate('Fact 11')),
993            'HEAD:_SCHEMA:INDI:_FA12'     => new CustomElement(I18N::translate('Fact 12')),
994            'HEAD:_SCHEMA:INDI:_FA13'     => new CustomElement(I18N::translate('Fact 13')),
995            'HEAD:_SCHEMA:INDI:_FA2'      => new CustomElement(I18N::translate('Fact 2')),
996            'HEAD:_SCHEMA:INDI:_FA3'      => new CustomElement(I18N::translate('Fact 3')),
997            'HEAD:_SCHEMA:INDI:_FA4'      => new CustomElement(I18N::translate('Fact 4')),
998            'HEAD:_SCHEMA:INDI:_FA5'      => new CustomElement(I18N::translate('Fact 5')),
999            'HEAD:_SCHEMA:INDI:_FA6'      => new CustomElement(I18N::translate('Fact 6')),
1000            'HEAD:_SCHEMA:INDI:_FA7'      => new CustomElement(I18N::translate('Fact 7')),
1001            'HEAD:_SCHEMA:INDI:_FA8'      => new CustomElement(I18N::translate('Fact 8')),
1002            'HEAD:_SCHEMA:INDI:_FA9'      => new CustomElement(I18N::translate('Fact 9')),
1003            'HEAD:_SCHEMA:INDI:_FREL'     => new CustomElement('Relationship to father'),
1004            'HEAD:_SCHEMA:INDI:_M*:LABL'  => new CustomElement(I18N::translate('Label')),
1005            'HEAD:_SCHEMA:INDI:_MREL'     => new CustomElement('Relationship to mother'),
1006            'INDI:*:SOUR:_APID'           => new CustomElement('Ancestry.com source identifier'),
1007            'INDI:*:SOUR:_LINK'           => new CustomElement('External link'),
1008            'INDI:NAME:_AKA'              => new NamePersonal(I18N::translate('Also known as'), []),
1009            'INDI:NAME:_MARNM'            => new NamePersonal(I18N::translate('Married name'), []),
1010            'INDI:_CIRC'                  => new CustomElement('Circumcision'),
1011            'INDI:_DCAUSE'                => new CustomElement(I18N::translate('Cause of death')),
1012            'INDI:_DEG'                   => new CustomElement(I18N::translate('Degree')),
1013            'INDI:_DNA'                   => new CustomElement(I18N::translate('DNA markers')),
1014            'INDI:_ELEC'                  => new CustomElement('Elected'),
1015            'INDI:_EMPLOY'                => new CustomElement('Employment'),
1016            'INDI:_EXCM'                  => new CustomElement('Excommunicated'),
1017            'INDI:_FA1'                   => new CustomElement('Fact 1'),
1018            'INDI:_FA10'                  => new CustomElement('Fact 10'),
1019            'INDI:_FA11'                  => new CustomElement('Fact 11'),
1020            'INDI:_FA12'                  => new CustomElement('Fact 12'),
1021            'INDI:_FA13'                  => new CustomElement('Fact 13'),
1022            'INDI:_FA2'                   => new CustomElement('Fact 2'),
1023            'INDI:_FA3'                   => new CustomElement('Fact 3'),
1024            'INDI:_FA4'                   => new CustomElement('Fact 4'),
1025            'INDI:_FA5'                   => new CustomElement('Fact 5'),
1026            'INDI:_FA6'                   => new CustomElement('Fact 6'),
1027            'INDI:_FA7'                   => new CustomElement('Fact 7'),
1028            'INDI:_FA8'                   => new CustomElement('Fact 8'),
1029            'INDI:_FA9'                   => new CustomElement('Fact 9'),
1030            'INDI:_MDCL'                  => new CustomElement('Medical'),
1031            'INDI:_MILT'                  => new CustomElement(I18N::translate('Military service')),
1032            'INDI:_MILTID'                => new CustomElement('Military ID number'),
1033            'INDI:_MISN'                  => new CustomElement('Mission'),
1034            'INDI:_NAMS'                  => new CustomElement(I18N::translate('Namesake')),
1035            'INDI:_UNKN'                  => new CustomElement(I18N::translate('Unknown')), // Special individual ID code for later file comparisons
1036        ];
1037    }
1038
1039    /**
1040     * @return array<string,ElementInterface>
1041     */
1042    private function gedcom53Tags(): array
1043    {
1044        return [
1045            'EVEN'                       => new CustomElement('Event'),
1046            'EVEN:*:*:NAME'              => new CustomElement(I18N::translate('Name')),
1047            'EVEN:*:AUDIO'               => new CustomElement(I18N::translate('Audio')),
1048            'EVEN:*:BROT'                => new CustomElement('Brother'),
1049            'EVEN:*:BUYR'                => new CustomElement('Buyer'),
1050            'EVEN:*:CHIL'                => new CustomElement('Child'),
1051            'EVEN:*:DATE'                => new DateValue('Date'),
1052            'EVEN:*:FATH'                => new CustomElement('Father'),
1053            'EVEN:*:GODP'                => new CustomElement('Godparent'),
1054            'EVEN:*:HDOH'                => new CustomElement('Head of household'),
1055            'EVEN:*:HEIR'                => new CustomElement('Heir'),
1056            'EVEN:*:HFAT'                => new CustomElement('Husband’s father'),
1057            'EVEN:*:HMOT'                => new CustomElement('Husband’s mother'),
1058            'EVEN:*:HUSB'                => new CustomElement('Husband'),
1059            'EVEN:*:IMAGE'               => new CustomElement('Image'),
1060            'EVEN:*:INDI'                => new CustomElement('Individual'),
1061            'EVEN:*:INFT'                => new CustomElement('Informant'),
1062            'EVEN:*:LEGA'                => new CustomElement('Legatee'),
1063            'EVEN:*:MBR'                 => new CustomElement('Member'),
1064            'EVEN:*:MOTH'                => new CustomElement('Mother'),
1065            'EVEN:*:OFFI'                => new CustomElement('Official'),
1066            'EVEN:*:PARE'                => new CustomElement('Parent'),
1067            'EVEN:*:PHOTO'               => new CustomElement(I18N::translate('Photo')),
1068            'EVEN:*:PHUS'                => new CustomElement('Previous husband'),
1069            'EVEN:*:PLAC'                => new PlaceName('Place'),
1070            'EVEN:*:PWIF'                => new CustomElement('Previous wife'),
1071            'EVEN:*:RECO'                => new CustomElement('Recorder'),
1072            'EVEN:*:REL'                 => new CustomElement('Relative'),
1073            'EVEN:*:SELR'                => new CustomElement('Seller'),
1074            'EVEN:*:SIBL'                => new CustomElement('Sibling'),
1075            'EVEN:*:SIST'                => new CustomElement('Sister'),
1076            'EVEN:*:SPOU'                => new CustomElement('Spouse'),
1077            'EVEN:*:TXPY'                => new CustomElement('Taxpayer'),
1078            'EVEN:*:VIDEO'               => new CustomElement(I18N::translate('Video')),
1079            'EVEN:*:WFAT'                => new CustomElement('Wife’s father'),
1080            'EVEN:*:WIFE'                => new CustomElement('Wife'),
1081            'EVEN:*:WITN'                => new CustomElement('Witness'),
1082            'EVEN:*:WMOT'                => new CustomElement('Wife’s mother'),
1083            'EVEN:TYPE'                  => new CustomElement('Type of event'),
1084            'FAM:*:*:QUAY'               => new CertaintyAssessment(I18N::translate('Quality of data')),
1085            'FAM:*:PLAC:SITE'            => new CustomElement('Site'),
1086            'FAM:*:QUAY'                 => new CertaintyAssessment(I18N::translate('Quality of data')),
1087            'FAM:AUDIO'                  => new CustomElement(I18N::translate('Audio')),
1088            'FAM:IMAGE'                  => new CustomElement('Image'),
1089            'FAM:PHOTO'                  => new CustomElement(I18N::translate('Photo')),
1090            'FAM:VIDEO'                  => new CustomElement(I18N::translate('Video')),
1091            'HEAD:SCHEMA'                => new CustomElement(I18N::translate('Unknown')),
1092            'HEAD:SCHEMA:FAM'            => new CustomElement(I18N::translate('Family')),
1093            'HEAD:SCHEMA:FAM:*:_*'       => new CustomElement('Custom event'),
1094            'HEAD:SCHEMA:FAM:*:_*:DEFN'  => new CustomElement('Definition'),
1095            'HEAD:SCHEMA:FAM:*:_*:ISA'   => new CustomElement('Type of event'),
1096            'HEAD:SCHEMA:FAM:*:_*:LABL'  => new CustomElement('Label'),
1097            'HEAD:SCHEMA:FAM:_*'         => new CustomElement('Custom event'),
1098            'HEAD:SCHEMA:FAM:_*:DEFN'    => new CustomElement('Definition'),
1099            'HEAD:SCHEMA:FAM:_*:ISA'     => new CustomElement('Type of event'),
1100            'HEAD:SCHEMA:FAM:_*:LABL'    => new CustomElement('Label'),
1101            'HEAD:SCHEMA:INDI'           => new CustomElement(I18N::translate('Individual')),
1102            'HEAD:SCHEMA:INDI:*:_*'      => new CustomElement('Custom event'),
1103            'HEAD:SCHEMA:INDI:*:_*:DEFN' => new CustomElement('Definition'),
1104            'HEAD:SCHEMA:INDI:*:_*:ISA'  => new CustomElement('Type of event'),
1105            'HEAD:SCHEMA:INDI:*:_*:LABL' => new CustomElement('Label'),
1106            'HEAD:SCHEMA:INDI:_*'        => new CustomElement('Custom event'),
1107            'HEAD:SCHEMA:INDI:_*:DEFN'   => new CustomElement('Definition'),
1108            'HEAD:SCHEMA:INDI:_*:ISA'    => new CustomElement('Type of event'),
1109            'HEAD:SCHEMA:INDI:_*:LABL'   => new CustomElement('Label'),
1110            'INDI:*:*:QUAY'              => new CertaintyAssessment(I18N::translate('Quality of data')),
1111            'INDI:*:PLAC:SITE'           => new CustomElement('Site'),
1112            'INDI:*:QUAY'                => new CertaintyAssessment(I18N::translate('Quality of data')),
1113            'INDI:AUDIO'                 => new CustomElement(I18N::translate('Audio')),
1114            'INDI:BURI:PLAC:CEME'        => new CustomElement(I18N::translate('Cemetery')),
1115            'INDI:BURI:PLAC:CEME:PLOT'   => new CustomElement('Burial plot'),
1116            'INDI:IMAGE'                 => new CustomElement('Image'),
1117            'INDI:NAMR'                  => new CustomElement(I18N::translate('Religious name')),
1118            'INDI:NAMS'                  => new CustomElement(I18N::translate('Namesake')),
1119            'INDI:PHOTO'                 => new CustomElement(I18N::translate('Photo')),
1120            'INDI:SIGN'                  => new CustomElement('Signature'),
1121            'INDI:VIDEO'                 => new CustomElement(I18N::translate('Video')),
1122            'REPO:CALN:ITEM'             => new CustomElement('Item'),
1123            'REPO:CALN:PAGE'             => new CustomElement('Page'),
1124            'REPO:CALN:SHEE'             => new CustomElement('Sheet'),
1125            'REPO:CNTC'                  => new CustomElement('Contact person'),
1126            'REPO:MEDI'                  => new SourceMediaType(I18N::translate('Media type')),
1127            'REPO:REFN'                  => new CustomElement('Reference number'),
1128            'SOUR:AUDIO'                 => new CustomElement(I18N::translate('Audio')),
1129            'SOUR:CENS'                  => new CustomElement('Census'),
1130            'SOUR:CENS:DATE'             => new CustomElement('Census'),
1131            'SOUR:CENS:DWEL'             => new CustomElement('Dwelling number'),
1132            'SOUR:CENS:FAMN'             => new CustomElement('Family number'),
1133            'SOUR:CENS:LINE'             => new CustomElement('Line number'),
1134            'SOUR:CLAS'                  => new CustomElement('Source classification'),
1135            'SOUR:CPLR'                  => new CustomElement('Compiler'),
1136            'SOUR:EDTR'                  => new CustomElement('Editor'),
1137            'SOUR:EVEN'                  => new CustomElement('Source events'),
1138            'SOUR:FIDE'                  => new CustomElement('Fidelity'),
1139            'SOUR:FILM'                  => new CustomElement(I18N::translate('Microfilm')),
1140            'SOUR:IMAGE'                 => new CustomElement('Image'),
1141            'SOUR:INDX'                  => new CustomElement('Indexed'),
1142            'SOUR:INTV'                  => new CustomElement('Interviewer'),
1143            'SOUR:ORIG'                  => new CustomElement('Originator'),
1144            'SOUR:ORIG:NAME'             => new CustomElement('Name'),
1145            'SOUR:ORIG:NOTE'             => new SubmitterText('Note'),
1146            'SOUR:ORIG:TYPE'             => new CustomElement('Type'),
1147            'SOUR:PERI'                  => new CustomElement('Date period'),
1148            'SOUR:PHOTO'                 => new CustomElement(I18N::translate('Photo')),
1149            'SOUR:PUBL:DATE'             => new DateValue('Date'),
1150            'SOUR:PUBL:EDTN'             => new CustomElement('Edition'),
1151            'SOUR:PUBL:ISSU'             => new CustomElement('Issue'),
1152            'SOUR:PUBL:LCCN'             => new CustomElement('Library of Congress call number'),
1153            'SOUR:PUBL:NAME'             => new CustomElement('Name'),
1154            'SOUR:PUBL:PUBR'             => new CustomElement('Publisher'),
1155            'SOUR:PUBL:SERS'             => new CustomElement('Series'),
1156            'SOUR:PUBL:TYPE'             => new CustomElement('Type'),
1157            'SOUR:QUAY'                  => new CertaintyAssessment(I18N::translate('Quality of data')),
1158            'SOUR:RECO'                  => new CustomElement('Recording agency?'),
1159            'SOUR:REFS'                  => new XrefSource('Referenced source'),
1160            'SOUR:REPO:DPRT:ARVL'        => new CustomElement('Departure'),
1161            'SOUR:REPO:DPRT:ARVL:DATE'   => new DateValue('Date'),
1162            'SOUR:REPO:DPRT:ARVL:PLAC'   => new PlaceName('Place'),
1163            'SOUR:REPO:NAME'             => new CustomElement('Name of vessel'),
1164            'SOUR:REPO:NOTE'             => new SubmitterText(I18N::translate('Note')),
1165            'SOUR:REPO:PORT'             => new CustomElement('Port'),
1166            'SOUR:REPO:PORT:ARVL'        => new CustomElement('Arrival'),
1167            'SOUR:REPO:PORT:ARVL:DATE'   => new DateValue('Date'),
1168            'SOUR:REPO:PORT:ARVL:PLAC'   => new PlaceName('Place'),
1169            'SOUR:REPO:TEXT'             => new TextFromSource(I18N::translate('Text')),
1170            'SOUR:SEQU'                  => new CustomElement('Sequence'),
1171            'SOUR:STAT'                  => new CustomElement('Search status'),
1172            'SOUR:STAT:DATE'             => new DateValue('Date'),
1173            'SOUR:TEXT'                  => new TextFromSource(I18N::translate('Text')),
1174            'SOUR:TYPE'                  => new CustomElement('Type of source'),
1175            'SOUR:VIDEO'                 => new CustomElement(I18N::translate('Video')),
1176            'SOUR:XLTR'                  => new CustomElement('Translator'),
1177        ];
1178    }
1179
1180    /**
1181     * @return array<string,ElementInterface>
1182     */
1183    private function gedcomLTags(): array
1184    {
1185        return [
1186            'FAM:*:ADDR:_NAME'               => new CustomElement('Name of addressee'),
1187            // I18N: https://gov.genealogy.net
1188            'FAM:*:PLAC:_GOV'                => new GovIdentifier(I18N::translate('GOV identifier')),
1189            'FAM:*:PLAC:_LOC'                => new XrefLocation(I18N::translate('Location')),
1190            // I18N: https://en.wikipedia.org/wiki/Maidenhead_Locator_System
1191            'FAM:*:PLAC:_MAIDENHEAD'         => new MaidenheadLocator(I18N::translate('Maidenhead location code')),
1192            'FAM:*:PLAC:_POST'               => new AddressPostalCode('Postal code'),
1193            'FAM:*:PLAC:_POST:DATE'          => new DateValue(I18N::translate('Date')),
1194            'FAM:*:_ASSO'                    => new XrefAssociate(I18N::translate('Associate')),
1195            'FAM:*:_ASSO:NOTE'               => new NoteStructure(I18N::translate('Note')),
1196            'FAM:*:_ASSO:RELA'               => new RelationIsDescriptor(I18N::translate('Relationship')),
1197            'FAM:*:_ASSO:SOUR'               => new XrefSource(I18N::translate('Source citation')),
1198            'FAM:*:_ASSO:SOUR:DATA'          => new SourceData(I18N::translate('Data')),
1199            'FAM:*:_ASSO:SOUR:DATA:DATE'     => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
1200            'FAM:*:_ASSO:SOUR:DATA:TEXT'     => new TextFromSource(I18N::translate('Text')),
1201            'FAM:*:_ASSO:SOUR:EVEN'          => new EventTypeCitedFrom(I18N::translate('Event')),
1202            'FAM:*:_ASSO:SOUR:EVEN:ROLE'     => new RoleInEvent(I18N::translate('Role')),
1203            'FAM:*:_ASSO:SOUR:NOTE'          => new NoteStructure(I18N::translate('Note')),
1204            'FAM:*:_ASSO:SOUR:OBJE'          => new XrefMedia(I18N::translate('Media object')),
1205            'FAM:*:_ASSO:SOUR:PAGE'          => new WhereWithinSource(I18N::translate('Citation details')),
1206            'FAM:*:_ASSO:SOUR:QUAY'          => new CertaintyAssessment(I18N::translate('Quality of data')),
1207            'FAM:*:_WITN'                    => new CustomElement('Witness'),
1208            'FAM:_STAT'                      => new FamilyStatusText(I18N::translate('Family status')),
1209            'FAM:_TODO'                      => new ResearchTask(I18N::translate('Research task'), ['DESC' => '1:1', '_CAT' => '0:1', '_PRTY' => '0:1', 'TYPE' => '0:1', 'NOTE' => '0:M', 'DATA' => '0:1', 'STAT' => '0:1', '_CDATE' => '0:1', '_RDATE' => '0:1', 'REPO' => '0:1', '_UID' => '0:M']),
1210            'FAM:_TODO:DATA'                 => new SubmitterText(I18N::translate('The solution')),
1211            'FAM:_TODO:DATE'                 => new DateValue(I18N::translate('Creation date')),
1212            'FAM:_TODO:DESC'                 => new CustomElement(I18N::translate('Description')),
1213            'FAM:_TODO:NOTE'                 => new SubmitterText(I18N::translate('The problem')),
1214            'FAM:_TODO:REPO'                 => new XrefRepository('Repository', []),
1215            'FAM:_TODO:STAT'                 => new ResearchTaskStatus(I18N::translate('Status')),
1216            'FAM:_TODO:TYPE'                 => new ResearchTaskType(I18N::translate('Type of research task')),
1217            'FAM:_TODO:_CAT'                 => new CustomElement(I18N::translate('Category')),
1218            'FAM:_TODO:_CDATE'               => new DateValue(I18N::translate('Completion date')),
1219            'FAM:_TODO:_PRTY'                => new ResearchTaskPriority(I18N::translate('Priority')),
1220            'FAM:_TODO:_RDATE'               => new DateValue(I18N::translate('Reminder date')),
1221            'FAM:_UID'                       => new PafUid(I18N::translate('Unique identifier')),
1222            'HEAD:GEDC:VERS:_ADDENDUM'       => new EmptyElement('GEDCOM-L'),
1223            'HEAD:GEDC:VERS:_ADDENDUM:VERS'  => new VersionNumber(I18N::translate('Version')),
1224            'HEAD:GEDC:VERS:_ADDENDUM:WWW'   => new AddressWebPage(I18N::translate('URL')),
1225            'HEAD:SOUR:CORP:ADDR:_NAME'      => new CustomElement('Name of addressee'),
1226            'HEAD:_SCHEMA'                   => new EmptyElement(I18N::translate('Schema')),
1227            'HEAD:_SCHEMA:*'                 => new EmptyElement(I18N::translate('Base GEDCOM tag')),
1228            'HEAD:_SCHEMA:*:*'               => new EmptyElement(I18N::translate('New GEDCOM tag')),
1229            'HEAD:_SCHEMA:*:*:*'             => new EmptyElement(I18N::translate('New GEDCOM tag')),
1230            'HEAD:_SCHEMA:*:*:*:*'           => new EmptyElement(I18N::translate('New GEDCOM tag')),
1231            'HEAD:_SCHEMA:*:*:*:*:*'         => new EmptyElement(I18N::translate('New GEDCOM tag')),
1232            'HEAD:_SCHEMA:*:*:*:*:*:*'       => new EmptyElement(I18N::translate('New GEDCOM tag')),
1233            'HEAD:_SCHEMA:*:*:*:*:*:*:_DEFN' => new EmptyElement(I18N::translate('Definition')),
1234            'HEAD:_SCHEMA:*:*:*:*:*:_DEFN'   => new EmptyElement(I18N::translate('Definition')),
1235            'HEAD:_SCHEMA:*:*:*:*:_DEFN'     => new EmptyElement(I18N::translate('Definition')),
1236            'HEAD:_SCHEMA:*:*:*:_DEFN'       => new EmptyElement(I18N::translate('Definition')),
1237            'HEAD:_SCHEMA:*:*:_DEFN'         => new EmptyElement(I18N::translate('Definition')),
1238            'INDI:*:ADDR:_NAME'              => new CustomElement('Name of addressee'),
1239            // I18N: https://gov.genealogy.net
1240            'INDI:*:PLAC:_GOV'               => new GovIdentifier(I18N::translate('GOV identifier')),
1241            'INDI:*:PLAC:_LOC'               => new XrefLocation(I18N::translate('Location')),
1242            // I18N: https://en.wikipedia.org/wiki/Maidenhead_Locator_System
1243            'INDI:*:PLAC:_MAIDENHEAD'        => new MaidenheadLocator(I18N::translate('Maidenhead location code')),
1244            'INDI:*:PLAC:_POST'              => new AddressPostalCode('Postal code'),
1245            'INDI:*:PLAC:_POST:DATE'         => new DateValue(I18N::translate('Date')),
1246            'INDI:*:_ASSO'                   => new XrefAssociate(I18N::translate('Associate')),
1247            'INDI:*:_ASSO:NOTE'              => new NoteStructure(I18N::translate('Note')),
1248            'INDI:*:_ASSO:RELA'              => new RelationIsDescriptor(I18N::translate('Relationship')),
1249            'INDI:*:_ASSO:SOUR'              => new XrefSource(I18N::translate('Source citation')),
1250            'INDI:*:_ASSO:SOUR:DATA'         => new SourceData(I18N::translate('Data')),
1251            'INDI:*:_ASSO:SOUR:DATA:DATE'    => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
1252            'INDI:*:_ASSO:SOUR:DATA:TEXT'    => new TextFromSource(I18N::translate('Text')),
1253            'INDI:*:_ASSO:SOUR:EVEN'         => new EventTypeCitedFrom(I18N::translate('Event')),
1254            'INDI:*:_ASSO:SOUR:EVEN:ROLE'    => new RoleInEvent(I18N::translate('Role')),
1255            'INDI:*:_ASSO:SOUR:NOTE'         => new NoteStructure(I18N::translate('Note')),
1256            'INDI:*:_ASSO:SOUR:OBJE'         => new XrefMedia(I18N::translate('Media object')),
1257            'INDI:*:_ASSO:SOUR:PAGE'         => new WhereWithinSource(I18N::translate('Citation details')),
1258            'INDI:*:_ASSO:SOUR:QUAY'         => new CertaintyAssessment(I18N::translate('Quality of data')),
1259            'INDI:*:_WITN'                   => new CustomElement('Witness'),
1260            'INDI:BAPM:_GODP'                => new CustomElement('Godparent'),
1261            'INDI:CHR:_GODP'                 => new CustomElement('Godparent'),
1262            'INDI:NAME:_RUFNAME'             => new NamePieceGiven(I18N::translate('Rufname')),
1263            'INDI:OBJE:_PRIM'                => new CustomElement(I18N::translate('Highlighted image')),
1264            'INDI:SEX'                       => new SexXValue(I18N::translate('Gender')),
1265            'INDI:_TODO'                     => new ResearchTask(I18N::translate('Research task')),
1266            'INDI:_TODO:DATA'                => new SubmitterText(I18N::translate('The solution')),
1267            'INDI:_TODO:DATE'                => new DateValue(I18N::translate('Creation date')),
1268            'INDI:_TODO:DESC'                => new CustomElement(I18N::translate('Description')),
1269            'INDI:_TODO:NOTE'                => new SubmitterText(I18N::translate('The problem')),
1270            'INDI:_TODO:REPO'                => new XrefRepository('Repository', []),
1271            'INDI:_TODO:STAT'                => new ResearchTaskStatus(I18N::translate('Status')),
1272            'INDI:_TODO:TYPE'                => new ResearchTaskType(I18N::translate('Type of research task')),
1273            'INDI:_TODO:_CAT'                => new CustomElement(I18N::translate('Category')),
1274            'INDI:_TODO:_CDATE'              => new DateValue(I18N::translate('Completion date')),
1275            'INDI:_TODO:_PRTY'               => new ResearchTaskPriority(I18N::translate('Priority')),
1276            'INDI:_TODO:_RDATE'              => new DateValue(I18N::translate('Reminder date')),
1277            'INDI:_UID'                      => new PafUid(I18N::translate('Unique identifier')),
1278            'NOTE:_UID'                      => new PafUid(I18N::translate('Unique identifier')),
1279            'OBJE:FILE:_PRIM'                => new CustomElement(I18N::translate('Highlighted image')),
1280            'OBJE:_UID'                      => new PafUid(I18N::translate('Unique identifier')),
1281            'REPO:ADDR:_NAME'                => new CustomElement('Name of addressee'),
1282            'REPO:_UID'                      => new PafUid(I18N::translate('Unique identifier')),
1283            'SOUR:_UID'                      => new PafUid(I18N::translate('Unique identifier')),
1284            'SUBM:ADDR:_NAME'                => new CustomElement('Name of addressee'),
1285            'SUBM:_UID'                      => new PafUid(I18N::translate('Unique identifier')),
1286            'SUBN:_UID'                      => new PafUid(I18N::translate('Unique identifier')),
1287            '_LOC'                           => new LocationRecord(I18N::translate('Location')),
1288            '_LOC:CHAN'                      => new Change(I18N::translate('Last change')),
1289            '_LOC:CHAN:DATE'                 => new ChangeDate(I18N::translate('Date of last change')),
1290            '_LOC:CHAN:DATE:TIME'            => new TimeValue(I18N::translate('Time')),
1291            '_LOC:CHAN:NOTE'                 => new NoteStructure(I18N::translate('Note')),
1292            '_LOC:EVEN'                      => new CustomEvent(I18N::translate('Event')),
1293            '_LOC:EVEN:DATE'                 => new DateValue(I18N::translate('Date of event')),
1294            '_LOC:EVEN:PLAC'                 => new PlaceName(I18N::translate('Place of event')),
1295            '_LOC:EVEN:PLAC:FONE'            => new PlacePhoneticVariation(I18N::translate('Phonetic place')),
1296            '_LOC:EVEN:PLAC:FONE:TYPE'       => new PhoneticType(I18N::translate('Type')),
1297            '_LOC:EVEN:PLAC:FORM'            => new PlaceHierarchy(I18N::translate('Format')),
1298            '_LOC:EVEN:PLAC:MAP'             => new EmptyElement(I18N::translate('Coordinates'), ['LATI' => '1:1', 'LONG' => '1:1']),
1299            '_LOC:EVEN:PLAC:MAP:LATI'        => new PlaceLatitude(I18N::translate('Latitude')),
1300            '_LOC:EVEN:PLAC:MAP:LONG'        => new PlaceLongtitude(I18N::translate('Longitude')),
1301            '_LOC:EVEN:PLAC:NOTE'            => new NoteStructure(I18N::translate('Note')),
1302            '_LOC:EVEN:PLAC:ROMN'            => new PlaceRomanizedVariation(I18N::translate('Romanized place')),
1303            '_LOC:EVEN:PLAC:ROMN:TYPE'       => new RomanizedType(I18N::translate('Type')),
1304            '_LOC:EVEN:TYPE'                 => new EventAttributeType(I18N::translate('Type of event')),
1305            '_LOC:EVEN:AGNC'                 => new ResponsibleAgency(I18N::translate('Agency')),
1306            '_LOC:EVEN:ADDR'                 => new AddressLine(I18N::translate('Address')),
1307            '_LOC:EVEN:ADDR:ADR1'            => new AddressLine1(I18N::translate('Address line 1')),
1308            '_LOC:EVEN:ADDR:ADR2'            => new AddressLine2(I18N::translate('Address line 2')),
1309            '_LOC:EVEN:ADDR:ADR3'            => new AddressLine3(I18N::translate('Address line 3')),
1310            '_LOC:EVEN:ADDR:CITY'            => new AddressCity(I18N::translate('City')),
1311            '_LOC:EVEN:ADDR:CTRY'            => new AddressCountry(I18N::translate('Country')),
1312            '_LOC:EVEN:ADDR:POST'            => new AddressPostalCode(I18N::translate('Postal code')),
1313            '_LOC:EVEN:ADDR:STAE'            => new AddressState(I18N::translate('State')),
1314            '_LOC:EVEN:CAUS'                 => new CauseOfEvent(I18N::translate('Cause')),
1315            '_LOC:EVEN:RELI'                 => new ReligiousAffiliation(I18N::translate('Religion'), []),
1316            '_LOC:EVEN:RESN'                 => new RestrictionNotice(I18N::translate('Restriction')),
1317            '_LOC:EVEN:SOUR'                 => new XrefSource(I18N::translate('Source citation')),
1318            '_LOC:EVEN:NOTE'                 => new NoteStructure(I18N::translate('Note')),
1319            '_LOC:EVEN:OBJE'                 => new XrefMedia(I18N::translate('Media object')),
1320            '_LOC:MAP'                       => new EmptyElement(I18N::translate('Coordinates'), ['LATI' => '1:1', 'LONG' => '1:1']),
1321            '_LOC:MAP:LATI'                  => new PlaceLatitude(I18N::translate('Latitude')),
1322            '_LOC:MAP:LONG'                  => new PlaceLongtitude(I18N::translate('Longitude')),
1323            '_LOC:NAME'                      => new PlaceName(I18N::translate('Place'), ['ABBR' => '0:1', 'DATE' => '0:1', 'LANG' => '0:1', 'SOUR' => '0:M']),
1324            '_LOC:NAME:ABBR'                 => new CustomElement(I18N::translate('Abbreviation')),
1325            '_LOC:NAME:ABBR:TYPE'            => new CustomElement(I18N::translate('Type of abbreviation')),
1326            '_LOC:NAME:DATE'                 => new DateValue(I18N::translate('Date')),
1327            '_LOC:NAME:LANG'                 => new LanguageId(I18N::translate('Language')),
1328            '_LOC:NAME:SOUR'                 => new XrefSource(I18N::translate('Source')),
1329            '_LOC:NOTE'                      => new NoteStructure(I18N::translate('Note')),
1330            '_LOC:OBJE'                      => new XrefMedia(I18N::translate('Media')),
1331            '_LOC:RELI'                      => new ReligiousAffiliation('Religion', []),
1332            '_LOC:SOUR'                      => new XrefSource(I18N::translate('Source')),
1333            '_LOC:SOUR:DATA'                 => new SourceData(I18N::translate('Data')),
1334            '_LOC:SOUR:DATA:DATE'            => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
1335            '_LOC:SOUR:DATA:TEXT'            => new TextFromSource(I18N::translate('Text')),
1336            '_LOC:SOUR:EVEN'                 => new EventTypeCitedFrom(I18N::translate('Event')),
1337            '_LOC:SOUR:EVEN:ROLE'            => new RoleInEvent(I18N::translate('Role')),
1338            '_LOC:SOUR:NOTE'                 => new NoteStructure(I18N::translate('Note')),
1339            '_LOC:SOUR:OBJE'                 => new XrefMedia(I18N::translate('Media object')),
1340            '_LOC:SOUR:PAGE'                 => new WhereWithinSource(I18N::translate('Citation details')),
1341            '_LOC:SOUR:QUAY'                 => new CertaintyAssessment(I18N::translate('Quality of data')),
1342            '_LOC:TYPE'                      => new CustomElement(I18N::translate('Type of location'), ['DATE' => '0:1', '_GOVTYPE' => '0:1', 'SOUR' => '0:M']),
1343            '_LOC:TYPE:DATE'                 => new DateValue(I18N::translate('Date')),
1344            '_LOC:TYPE:SOUR'                 => new XrefSource(I18N::translate('Source')),
1345            '_LOC:TYPE:_GOVTYPE'             => new CustomElement('GOV identifier type'),
1346            '_LOC:_AIDN'                     => new CustomElement('Administrative ID'),
1347            '_LOC:_AIDN:DATE'                => new DateValue(I18N::translate('Date')),
1348            '_LOC:_AIDN:SOUR'                => new XrefSource(I18N::translate('Source')),
1349            '_LOC:_AIDN:TYPE'                => new CustomElement(I18N::translate('Type of administrative ID')),
1350            '_LOC:_DMGD'                     => new CustomElement('Demographic data'),
1351            '_LOC:_DMGD:DATE'                => new DateValue(I18N::translate('Date')),
1352            '_LOC:_DMGD:SOUR'                => new XrefSource(I18N::translate('Source')),
1353            '_LOC:_DMGD:TYPE'                => new CustomElement(I18N::translate('Type of demographic data')),
1354            // I18N: https://gov.genealogy.net
1355            '_LOC:_GOV'                      => new GovIdentifier(I18N::translate('GOV identifier')),
1356            '_LOC:_LOC'                      => new XrefLocation(I18N::translate('Parent'), ['DATE' => '0:1', 'SOUR' => '0:M', 'TYPE' => '0:1']),
1357            '_LOC:_LOC:DATE'                 => new DateValue(I18N::translate('Date')),
1358            '_LOC:_LOC:SOUR'                 => new XrefSource(I18N::translate('Source')),
1359            '_LOC:_LOC:TYPE'                 => new HierarchicalRelationship(I18N::translate('Hierarchical relationship')),
1360            // I18N: https://en.wikipedia.org/wiki/Maidenhead_Locator_System
1361            '_LOC:_MAIDENHEAD'               => new MaidenheadLocator(I18N::translate('Maidenhead location code')),
1362            '_LOC:_POST'                     => new AddressPostalCode(I18N::translate('Postal code')),
1363            '_LOC:_POST:DATE'                => new DateValue(I18N::translate('Date')),
1364            '_LOC:_POST:SOUR'                => new XrefSource(I18N::translate('Source')),
1365            '_LOC:_UID'                      => new PafUid(I18N::translate('Unique identifier')),
1366            '_LOC:*:SOUR:DATA'               => new SourceData(I18N::translate('Data')),
1367            '_LOC:*:SOUR:DATA:DATE'          => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
1368            '_LOC:*:SOUR:DATA:TEXT'          => new TextFromSource(I18N::translate('Text')),
1369            '_LOC:*:SOUR:EVEN'               => new EventTypeCitedFrom(I18N::translate('Event')),
1370            '_LOC:*:SOUR:EVEN:ROLE'          => new RoleInEvent(I18N::translate('Role')),
1371            '_LOC:*:SOUR:NOTE'               => new NoteStructure(I18N::translate('Note')),
1372            '_LOC:*:SOUR:OBJE'               => new XrefMedia(I18N::translate('Media object')),
1373            '_LOC:*:SOUR:PAGE'               => new WhereWithinSource(I18N::translate('Citation details')),
1374            '_LOC:*:SOUR:QUAY'               => new CertaintyAssessment(I18N::translate('Quality of data')),
1375        ];
1376    }
1377
1378    /**
1379     * @return array<string,ElementInterface>
1380     */
1381    private function genPlusWinTags(): array
1382    {
1383        return [
1384            'FAM:*:ADDR:_NUM'         => new CustomElement(I18N::translate('House number')),
1385            'FAM:*:ADDR:_STRASSE'     => new CustomElement(I18N::translate('Street name')),
1386            'FAM:*:DATE:_ZUS'         => new CustomElement(I18N::translate('Additional information')),
1387            'FAM:*:OBJE:_PRIM'        => new CustomElement(I18N::translate('Highlighted image')),
1388            'FAM:*:PLAC:_AON'         => new CustomElement(I18N::translate('Alternative place name')),
1389            // I18N: https://foko.genealogy.net
1390            'FAM:*:PLAC:_FCTRY'       => new CustomElement(I18N::translate('FOKO country')),
1391            // I18N: https://foko.genealogy.net
1392            'FAM:*:PLAC:_FSTAE'       => new CustomElement(I18N::translate('FOKO country')),
1393            // I18N: https://gov.genealogy.net
1394            'FAM:*:PLAC:_GOV'         => new GovIdentifier(I18N::translate('GOV identifier')),
1395            // I18N: https://en.wikipedia.org/wiki/Maidenhead_Locator_System
1396            'FAM:*:PLAC:_MAIDENHEAD'  => new MaidenheadLocator(I18N::translate('Maidenhead location code')),
1397            'FAM:*:PLAC:_POST'        => new AddressPostalCode(I18N::translate('Postal code')),
1398            'FAM:*:PLAC:_SIC'         => new CustomElement(I18N::translate('Reliability of the information')),
1399            'FAM:*:PLAC:_ZUS'         => new CustomElement(I18N::translate('Additional information')),
1400            'FAM:*:SOUR:_ORI'         => new TextFromSource(I18N::translate('Original text')),
1401            'FAM:*:SOUR:_ZUS'         => new CustomElement(I18N::translate('Additional information')),
1402            'FAM:*:SOUR:PAGE:_ZUS'    => new CustomElement(I18N::translate('Additional information')),
1403            'FAM:*:_ASSO'             => new XrefAssociate(I18N::translate('Associate')),
1404            'FAM:*:_CERT'             => new CustomElement(I18N::translate('Certificate number')),
1405            'FAM:*:_COM'              => new CustomElement(I18N::translate('Comment')),
1406            'FAM:*:_SITE'             => new CustomElement(I18N::translate('Extra information')),
1407            'FAM:*:_WITN'             => new CustomElement(I18N::translate('Witness')),
1408            'FAM:OBJE:_PRIM'          => new CustomElement(I18N::translate('Highlighted image')),
1409            'FAM:SOUR:_ORI'           => new TextFromSource(I18N::translate('Original text')),
1410            'FAM:SOUR:_ZUS'           => new CustomElement(I18N::translate('Additional information')),
1411            'FAM:SOUR:PAGE:_ZUS'      => new CustomElement(I18N::translate('Additional information')),
1412            'FAM:_CREAT'              => new DateValue(I18N::translate('Creation date')),
1413            'FAM:_LIV'                => new CustomElement(I18N::translate('Cohabitation')),
1414            'FAM:_NAME'               => new CustomElement(I18N::translate('Joint family name')),
1415            'FAM:_UID'                => new PafUid(I18N::translate('Unique identifier')),
1416            'INDI:*:ADDR:_NUM'        => new CustomElement(I18N::translate('House number')),
1417            'INDI:*:ADDR:_STRASSE'    => new CustomElement(I18N::translate('Street name')),
1418            'INDI:*:DATE:_ZUS'        => new CustomElement(I18N::translate('Additional information')),
1419            'INDI:*:OBJE:_PRIM'       => new CustomElement(I18N::translate('Highlighted image')),
1420            'INDI:*:PLAC:_AON'        => new CustomElement(I18N::translate('Alternative place name')),
1421            // I18N: https://foko.genealogy.net
1422            'INDI:*:PLAC:_FCTRY'      => new CustomElement(I18N::translate('FOKO country')),
1423            // I18N: https://foko.genealogy.net
1424            'INDI:*:PLAC:_FSTAE'      => new CustomElement(I18N::translate('FOKO country')),
1425            // I18N: https://gov.genealogy.net
1426            'INDI:*:PLAC:_GOV'        => new GovIdentifier(I18N::translate('GOV identifier')),
1427            // I18N: https://en.wikipedia.org/wiki/Maidenhead_Locator_System
1428            'INDI:*:PLAC:_MAIDENHEAD' => new MaidenheadLocator(I18N::translate('Maidenhead location code')),
1429            'INDI:*:PLAC:_POST'       => new AddressPostalCode(I18N::translate('Postal code')),
1430            'INDI:*:PLAC:_SIC'        => new CustomElement(I18N::translate('Reliability of the information')),
1431            'INDI:*:PLAC:_ZUS'        => new CustomElement(I18N::translate('Additional information')),
1432            'INDI:*:SOUR:_ORI'        => new TextFromSource(I18N::translate('Original text')),
1433            'INDI:*:SOUR:_ZUS'        => new CustomElement(I18N::translate('Additional information')),
1434            'INDI:*:SOUR:PAGE:_ZUS'   => new CustomElement(I18N::translate('Additional information')),
1435            'INDI:*:_ASSO'            => new XrefAssociate(I18N::translate('Associate')),
1436            'INDI:*:_CERT'            => new CustomElement(I18N::translate('Certificate number')),
1437            'INDI:*:_COM'             => new CustomElement(I18N::translate('Comment')),
1438            'INDI:*:_SITE'            => new CustomElement(I18N::translate('Extra information')),
1439            'INDI:*:_WITN'            => new CustomElement(I18N::translate('Witness')),
1440            'INDI:BAPM:_GODP'         => new CustomElement(I18N::translate('Also known as')),
1441            'INDI:CHR:_GODP'          => new CustomElement(I18N::translate('Godparent')),
1442            'INDI:OBJE:_PRIM'         => new CustomElement(I18N::translate('Highlighted image')),
1443            'INDI:SOUR:_ORI'          => new TextFromSource(I18N::translate('Original text')),
1444            'INDI:SOUR:_ZUS'          => new CustomElement(I18N::translate('Additional information')),
1445            'INDI:SOUR:PAGE:_ZUS'     => new CustomElement(I18N::translate('Additional information')),
1446            'INDI:NAME:_AKA'          => new CustomElement(I18N::translate('Also known as')),
1447            // https://en.wikipedia.org/wiki/Rufname
1448            'INDI:NAME:RUFN'          => new CustomElement(I18N::translate('Rufname')),
1449            'INDI:_CREAT'             => new CustomElement(I18N::translate('Creation date')),
1450            'INDI:_HEIM'              => new CustomElement(/* I18N: German Bürgerort */ I18N::translate('Place of citizenship')),
1451            'INDI:_UID'               => new PafUid(I18N::translate('Unique identifier')),
1452            'NOTE:_CREAT'             => new DateValue(I18N::translate('Creation date')),
1453            'NOTE:_UID'               => new PafUid(I18N::translate('Unique identifier')),
1454            'OBJE:_CREAT'             => new DateValue(I18N::translate('Creation date')),
1455            'OBJE:_UID'               => new PafUid(I18N::translate('Unique identifier')),
1456            'REPO:_CREAT'             => new DateValue(I18N::translate('Creation date')),
1457            'REPO:_UID'               => new PafUid(I18N::translate('Unique identifier')),
1458            'SOUR:_CREAT'             => new DateValue(I18N::translate('Creation date')),
1459            'SOUR:_KTIT'              => new SourceFiledByEntry(I18N::translate('Abbreviation')),
1460            'SOUR:_UID'               => new PafUid(I18N::translate('Unique identifier')),
1461        ];
1462    }
1463
1464    /**
1465     * @see http://support.legacyfamilytree.com/article/AA-00520/0/GEDCOM-Files-custom-tags-in-Legacy.html
1466     *
1467     * @return array<string,ElementInterface>
1468     */
1469    private function legacyTags(): array
1470    {
1471        return [
1472            'FAM:*:ADDR:_PRIV'             => new CustomElement(I18N::translate('Private')),
1473            'FAM:*:PLAC:_VERI'             => new CustomElement(I18N::translate('Verified')),
1474            'FAM:*:SOUR:_VERI'             => new CustomElement(I18N::translate('Verified')),
1475            'FAM:*:_PRIV'                  => new CustomElement(I18N::translate('Private')),
1476            'FAM:CHIL:_FREL'               => new CustomElement(I18N::translate('Relationship to father')),
1477            'FAM:CHIL:_MREL'               => new CustomElement(I18N::translate('Relationship to mother')),
1478            'FAM:CHIL:_STAT'               => new CustomElement(I18N::translate('Status')),
1479            'FAM:EVEN:_OVER'               => new CustomElement('Event sentence override'),
1480            'FAM:MARR:_STAT'               => new CustomElement(I18N::translate('Status')),
1481            'FAM:SOUR:_VERI'               => new CustomElement(I18N::translate('Verified')),
1482            'FAM:_NONE'                    => new CustomElement(I18N::translate('No children')),
1483            'FAM:_UID'                     => new PafUid(I18N::translate('Unique identifier')),
1484            'HEAD:_EVENT_DEFN'             => new CustomElement('Event definition'),
1485            'HEAD:_EVENT_DEFN:_CONF_FLAG'  => new CustomElement(I18N::translate('Private')),
1486            'HEAD:_EVENT_DEFN:_DATE_TYPE'  => new CustomElement(I18N::translate('Date')),
1487            'HEAD:_EVENT_DEFN:_DESC_FLAG'  => new CustomElement(I18N::translate('Description')),
1488            'HEAD:_EVENT_DEFN:_PLACE_TYPE' => new CustomElement(I18N::translate('Place')),
1489            'HEAD:_EVENT_DEFN:_PP_EXCLUDE' => new CustomElement('Exclude event from potential problems report'),
1490            'HEAD:_EVENT_DEFN:_SEN1'       => new CustomElement('Event sentence definition'),
1491            'HEAD:_EVENT_DEFN:_SEN2'       => new CustomElement('Event sentence definition'),
1492            'HEAD:_EVENT_DEFN:_SEN3'       => new CustomElement('Event sentence definition'),
1493            'HEAD:_EVENT_DEFN:_SEN4'       => new CustomElement('Event sentence definition'),
1494            'HEAD:_EVENT_DEFN:_SEN5'       => new CustomElement('Event sentence definition'),
1495            'HEAD:_EVENT_DEFN:_SEN6'       => new CustomElement('Event sentence definition'),
1496            'HEAD:_EVENT_DEFN:_SEN7'       => new CustomElement('Event sentence definition'),
1497            'HEAD:_EVENT_DEFN:_SEN8'       => new CustomElement('Event sentence definition'),
1498            'HEAD:_EVENT_DEFN:_SENDOF'     => new CustomElement('Event sentence, female, date only'),
1499            'HEAD:_EVENT_DEFN:_SENDOM'     => new CustomElement('Event sentence, male, date only'),
1500            'HEAD:_EVENT_DEFN:_SENDOU'     => new CustomElement('Event sentence, unknown sex, date only'),
1501            'HEAD:_EVENT_DEFN:_SENDPF'     => new CustomElement('Event sentence, female, date and place'),
1502            'HEAD:_EVENT_DEFN:_SENDPM'     => new CustomElement('Event sentence, male, date and place'),
1503            'HEAD:_EVENT_DEFN:_SENDPU'     => new CustomElement('Event sentence, unknown sex, date and place'),
1504            'HEAD:_EVENT_DEFN:_SENF'       => new CustomElement('Event sentence, female'),
1505            'HEAD:_EVENT_DEFN:_SENM'       => new CustomElement('Event sentence, male'),
1506            'HEAD:_EVENT_DEFN:_SENPOF'     => new CustomElement('Event sentence, unknown sex'),
1507            'HEAD:_EVENT_DEFN:_SENPOM'     => new CustomElement('Event sentence, female, place only'),
1508            'HEAD:_EVENT_DEFN:_SENPOU'     => new CustomElement('Event sentence, male, place only'),
1509            'HEAD:_EVENT_DEFN:_SENU'       => new CustomElement('Event sentence, unknown sex, place only'),
1510            'HEAD:_PLAC_DEFN'              => new CustomElement('Place definition'),
1511            'HEAD:_PLAC_DEFN:_PREP'        => new CustomElement('Place preposition'),
1512            'INDI:*:ADDR:_EMAIL'           => new CustomElement(I18N::translate('Email')),
1513            'INDI:*:ADDR:_LIST1'           => new CustomElement('Include in the “newsletter” group'),
1514            'INDI:*:ADDR:_LIST2'           => new CustomElement('Include in the “family association” group'),
1515            'INDI:*:ADDR:_LIST3'           => new CustomElement('Include in the “birthday” group'),
1516            'INDI:*:ADDR:_LIST4'           => new CustomElement('Include in the “research” group'),
1517            'INDI:*:ADDR:_LIST5'           => new CustomElement('Include in the “christmas” group'),
1518            'INDI:*:ADDR:_LIST6'           => new CustomElement('Include in the “holiday” group'),
1519            'INDI:*:ADDR:_NAME'            => new CustomElement(I18N::translate('Name of addressee')),
1520            'INDI:*:ADDR:_PRIV'            => new CustomElement(I18N::translate('Private')),
1521            'INDI:*:ADDR:_SORT'            => new CustomElement('The spelling of a name to be used when sorting addresses for a report'),
1522            'INDI:*:ADDR:_TAG'             => new CustomElement('Tag'),
1523            'INDI:*:PLAC:_TAG'             => new CustomElement('Tag'),
1524            'INDI:*:PLAC:_VERI'            => new CustomElement(I18N::translate('Verified')),
1525            'INDI:*:SOUR:_VERI'            => new CustomElement(I18N::translate('Verified')),
1526            'INDI:*:_PRIV'                 => new CustomElement(I18N::translate('Private')),
1527            'INDI:EVEN:_OVER'              => new CustomElement('Event sentence override'),
1528            'INDI:SOUR:_VERI'              => new CustomElement(I18N::translate('Verified')),
1529            'INDI:_TAG'                    => new CustomElement('Tag'),
1530            'INDI:_TAG2'                   => new CustomElement('Tag #2'),
1531            'INDI:_TAG3'                   => new CustomElement('Tag #3'),
1532            'INDI:_TAG4'                   => new CustomElement('Tag #4'),
1533            'INDI:_TAG5'                   => new CustomElement('Tag #5'),
1534            'INDI:_TAG6'                   => new CustomElement('Tag #6'),
1535            'INDI:_TAG7'                   => new CustomElement('Tag #7'),
1536            'INDI:_TAG8'                   => new CustomElement('Tag #8'),
1537            'INDI:_TAG9'                   => new CustomElement('Tag #9'),
1538            'INDI:_TODO'                   => new CustomElement(I18N::translate('Research task')),
1539            'INDI:_TODO:PRTY'              => new CustomElement(I18N::translate('Priority')),
1540            'INDI:_TODO:_CAT'              => new CustomElement(I18N::translate('Category')),
1541            'INDI:_TODO:_CDATE'            => new CustomElement(I18N::translate('Completion date')),
1542            'INDI:_TODO:_LOCL'             => new CustomElement(I18N::translate('Location')),
1543            'INDI:_TODO:_RDATE'            => new CustomElement(I18N::translate('Reminder date')),
1544            'INDI:_UID'                    => new PafUid(I18N::translate('Unique identifier')),
1545            'INDI:_URL'                    => new AddressWebPage(I18N::translate('URL')),
1546            'OBJE:_DATE'                   => new CustomElement(I18N::translate('Date')),
1547            'OBJE:_PRIM'                   => new CustomElement(I18N::translate('Highlighted image')),
1548            'OBJE:_SCBK'                   => new CustomElement(I18N::translate('Scrapbook')),
1549            'OBJE:_SOUND'                  => new CustomElement(I18N::translate('Audio')),
1550            'OBJE:_TYPE'                   => new CustomElement(I18N::translate('Type')),
1551            'OBJE:_UID'                    => new PafUid(I18N::translate('Unique identifier')),
1552            'REPO:_UID'                    => new PafUid(I18N::translate('Unique identifier')),
1553            'SOUR:_ITALIC'                 => new CustomElement('The source title should be printed in italic on reports'),
1554            'SOUR:_PAREN'                  => new CustomElement('The source title should be printed within parentheses on reports'),
1555            'SOUR:_QUOTED'                 => new CustomElement('The source title should be printed within quotes on reports'),
1556            'SOUR:_TAG'                    => new CustomElement('Exclude the source citation detail on reports'),
1557            'SOUR:_TAG2'                   => new CustomElement('Exclude the source citation on reports'),
1558            'SOUR:_TAG3'                   => new CustomElement('Include the source citation detail text on reports'),
1559            'SOUR:_TAG4'                   => new CustomElement('Include the source citation detail notes on reports'),
1560            'SOUR:_UID'                    => new PafUid(I18N::translate('Unique identifier')),
1561        ];
1562    }
1563
1564    /**
1565     * @return array<string,ElementInterface>
1566     */
1567    private function personalAncestralFileTags(): array
1568    {
1569        return [
1570            'FAM:_UID'        => new PafUid(I18N::translate('Unique identifier')),
1571            'INDI:NAME:_ADPN' => new NamePersonal(I18N::translate('Adopted name'), []),
1572            'INDI:NAME:_AKA'  => new NamePersonal(I18N::translate('Also known as'), []),
1573            'INDI:NAME:_AKAN' => new NamePersonal(I18N::translate('Also known as'), []),
1574            'INDI:ADDR'       => new AddressLine(I18N::translate('Address')),
1575            'INDI:ADDR:ADR1'  => new AddressLine1(I18N::translate('Address line 1')),
1576            'INDI:ADDR:ADR2'  => new AddressLine2(I18N::translate('Address line 2')),
1577            'INDI:ADDR:CITY'  => new AddressCity(I18N::translate('City')),
1578            'INDI:ADDR:CTRY'  => new AddressCountry(I18N::translate('Country')),
1579            'INDI:ADDR:POST'  => new AddressPostalCode(I18N::translate('Postal code')),
1580            'INDI:ADDR:STAE'  => new AddressState(I18N::translate('State')),
1581            'INDI:ADDR:_NAME' => new CustomElement(I18N::translate('Name of addressee')),
1582            'INDI:EMAIL'      => new AddressEmail(I18N::translate('Email address')),
1583            'INDI:FAX'        => new AddressFax(I18N::translate('Fax')),
1584            'INDI:PHON'       => new PhoneNumber(I18N::translate('Phone')),
1585            'INDI:URL'        => new CustomElement(I18N::translate('URL')),
1586            'INDI:_UID'       => new PafUid(I18N::translate('Unique identifier')),
1587            'OBJE:_UID'       => new PafUid(I18N::translate('Unique identifier')),
1588            'REPO:_UID'       => new PafUid(I18N::translate('Unique identifier')),
1589            'SOUR:_UID'       => new PafUid(I18N::translate('Unique identifier')),
1590        ];
1591    }
1592
1593    /**
1594     * @return array<string,ElementInterface>
1595     */
1596    private function phpGedViewTags(): array
1597    {
1598        return [
1599            'FAM:CHAN:_PGVU'        => new WebtreesUser(I18N::translate('Author of last change')),
1600            'FAM:COMM'              => new CustomElement(I18N::translate('Comment')),
1601            'INDI:*:ASSO'           => new XrefAssociate(I18N::translate('Associate')),
1602            'INDI:*:ASSO:RELA'      => new RelationIsDescriptor(I18N::translate('Relationship')),
1603            'INDI:*:PLAC:_HEB'      => new NoteStructure(I18N::translate('Place in Hebrew')),
1604            'INDI:ADDR'             => new AddressLine(I18N::translate('Address')),
1605            'INDI:BIRT:DATE:TIME'   => new TimeValue(I18N::translate('Time')),
1606            'INDI:BURI:CEME'        => new CustomElement(I18N::translate('Cemetery')),
1607            'INDI:CHAN:_PGVU'       => new WebtreesUser(I18N::translate('Author of last change')),
1608            'INDI:COMM'             => new CustomElement(I18N::translate('Comment')),
1609            'INDI:DEAT:DATE:TIME'   => new TimeValue(I18N::translate('Time')),
1610            'INDI:EMAIL'            => new AddressEmail(I18N::translate('Email address')),
1611            'INDI:NAME:_HEB'        => new NamePersonal(I18N::translate('Name in Hebrew'), []),
1612            'INDI:_FNRL'            => new CustomIndividualEvent(I18N::translate('Funeral')),
1613            'INDI:_HOL'             => new CustomIndividualEvent(I18N::translate('Holocaust')),
1614            'INDI:_MILI'            => new CustomIndividualEvent(I18N::translate('Military')),
1615            'INDI:_PGV_OBJS'        => new XrefMedia(I18N::translate('Re-order media')),
1616            'NOTE:CHAN:_PGVU'       => new WebtreesUser(I18N::translate('Author of last change')),
1617            'OBJE:CHAN:_PGVU'       => new WebtreesUser(I18N::translate('Author of last change')),
1618            'OBJE:_PRIM'            => new CustomElement(I18N::translate('Highlighted image')),
1619            'OBJE:_THUM'            => new CustomElement(I18N::translate('Thumbnail image')),
1620            'REPO:CHAN:_PGVU'       => new WebtreesUser(I18N::translate('Author of last change')),
1621            'SOUR:CHAN:_PGVU'       => new WebtreesUser(I18N::translate('Author of last change')),
1622            'SOUR:SERV'             => new CustomElement(I18N::translate('Remote server')),
1623            'SOUR:URL'              => new AddressWebPage(I18N::translate('URL')),
1624            'SOUR:URL:TYPE'         => new CustomElement(I18N::translate('Type')), // e.g. "FamilySearch"
1625            'SOUR:URL:_BLOCK'       => new CustomElement(I18N::translate('Block')), // "e.g. "false"
1626            'SOUR:_DBID'            => new CustomElement(I18N::translate('Database name')),
1627            'SOUR:_DBID:_PASS'      => new CustomElement(I18N::translate('Database password')),
1628            'SOUR:_DBID:_PASS:RESN' => new RestrictionNotice(I18N::translate('Restriction')),
1629            'SOUR:_DBID:_USER'      => new CustomElement(I18N::translate('Database user account')),
1630        ];
1631    }
1632
1633    /**
1634     * @return array<string,ElementInterface>
1635     */
1636    private function reunionTags(): array
1637    {
1638        return [
1639            'FAM:_UID'   => new PafUid(I18N::translate('Unique identifier')),
1640            'INDI:CITN'  => new CustomElement(I18N::translate('Citizenship')),
1641            'INDI:EMAL'  => new AddressEmail(I18N::translate('Email address')),
1642            'INDI:_LEGA' => new CustomElement(I18N::translate('Legatee')),
1643            'INDI:_MDCL' => new CustomElement(I18N::translate('Medical')),
1644            'INDI:_PURC' => new CustomElement('Land purchase'),
1645            'INDI:_SALE' => new CustomElement('Land sale'),
1646            'INDI:_UID'  => new PafUid(I18N::translate('Unique identifier')),
1647            'OBJE:_UID'  => new PafUid(I18N::translate('Unique identifier')),
1648            'REPO:_UID'  => new PafUid(I18N::translate('Unique identifier')),
1649            'SOUR:_UID'  => new PafUid(I18N::translate('Unique identifier')),
1650        ];
1651    }
1652
1653    /**
1654     * @return array<string,ElementInterface>
1655     */
1656    private function rootsMagicTags(): array
1657    {
1658        return [
1659            'FAM:_UID'          => new PafUid(I18N::translate('Unique identifier')),
1660            'INDI:_DNA'         => new CustomElement(I18N::translate('DNA markers')),
1661            'INDI:_UID'         => new PafUid(I18N::translate('Unique identifier')),
1662            'INDI:_WEBTAG'      => new CustomElement(I18N::translate('External link')),
1663            'INDI:_WEBTAG:NAME' => new CustomElement(I18N::translate('Text')),
1664            'INDI:_WEBTAG:URL'  => new AddressWebPage(I18N::translate('URL')),
1665            'OBJE:_UID'         => new PafUid(I18N::translate('Unique identifier')),
1666            'REPO:_UID'         => new PafUid(I18N::translate('Unique identifier')),
1667            'SOUR:_BIBL'        => new CustomElement(I18N::translate('Bibliography')),
1668            'SOUR:_SUBQ'        => new CustomElement(I18N::translate('Abbreviation')),
1669            'SOUR:_UID'         => new PafUid(I18N::translate('Unique identifier')),
1670        ];
1671    }
1672
1673    /**
1674     * @return array<string,ElementInterface>
1675     */
1676    private function theMasterGenealogistTags(): array
1677    {
1678        return [
1679            'INDI:*:_SDATE' => new DateValue(I18N::translate('Sort date')),
1680            'INDI:NAME:_DATE'  => new DateValue(I18N::translate('Date')),
1681        ];
1682    }
1683
1684    /**
1685     * Custom tags for webtrees.
1686     *
1687     * @return array<string,ElementInterface>
1688     */
1689    private function webtreesTags(): array
1690    {
1691        return [
1692            'FAM:CHAN:_WT_USER'           => new WebtreesUser(I18N::translate('Author of last change')),
1693            'FAM:*:_ASSO'                 => new XrefAssociate(I18N::translate('Associate')),
1694            'FAM:*:_ASSO:NOTE'            => new NoteStructure(I18N::translate('Note')),
1695            'FAM:*:_ASSO:RELA'            => new RelationIsDescriptor(I18N::translate('Relationship')),
1696            'FAM:*:_ASSO:SOUR'            => new XrefSource(I18N::translate('Source citation')),
1697            'FAM:*:_ASSO:SOUR:DATA'       => new SourceData(I18N::translate('Data')),
1698            'FAM:*:_ASSO:SOUR:DATA:DATE'  => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
1699            'FAM:*:_ASSO:SOUR:DATA:TEXT'  => new TextFromSource(I18N::translate('Text')),
1700            'FAM:*:_ASSO:SOUR:EVEN'       => new EventTypeCitedFrom(I18N::translate('Event')),
1701            'FAM:*:_ASSO:SOUR:EVEN:ROLE'  => new RoleInEvent(I18N::translate('Role')),
1702            'FAM:*:_ASSO:SOUR:NOTE'       => new NoteStructure(I18N::translate('Note')),
1703            'FAM:*:_ASSO:SOUR:OBJE'       => new XrefMedia(I18N::translate('Media object')),
1704            'FAM:*:_ASSO:SOUR:PAGE'       => new WhereWithinSource(I18N::translate('Citation details')),
1705            'FAM:*:_ASSO:SOUR:QUAY'       => new CertaintyAssessment(I18N::translate('Quality of data')),
1706            'INDI:CHAN:_WT_USER'          => new WebtreesUser(I18N::translate('Author of last change')),
1707            'INDI:*:_ASSO'                => new XrefAssociate(I18N::translate('Associate')),
1708            'INDI:*:_ASSO:NOTE'           => new NoteStructure(I18N::translate('Note')),
1709            'INDI:*:_ASSO:RELA'           => new RelationIsDescriptor(I18N::translate('Relationship')),
1710            'INDI:*:_ASSO:SOUR'           => new XrefSource(I18N::translate('Source citation')),
1711            'INDI:*:_ASSO:SOUR:DATA'      => new SourceData(I18N::translate('Data')),
1712            'INDI:*:_ASSO:SOUR:DATA:DATE' => new EntryRecordingDate(I18N::translate('Date of entry in original source')),
1713            'INDI:*:_ASSO:SOUR:DATA:TEXT' => new TextFromSource(I18N::translate('Text')),
1714            'INDI:*:_ASSO:SOUR:EVEN'      => new EventTypeCitedFrom(I18N::translate('Event')),
1715            'INDI:*:_ASSO:SOUR:EVEN:ROLE' => new RoleInEvent(I18N::translate('Role')),
1716            'INDI:*:_ASSO:SOUR:NOTE'      => new NoteStructure(I18N::translate('Note')),
1717            'INDI:*:_ASSO:SOUR:OBJE'      => new XrefMedia(I18N::translate('Media object')),
1718            'INDI:*:_ASSO:SOUR:PAGE'      => new WhereWithinSource(I18N::translate('Citation details')),
1719            'INDI:*:_ASSO:SOUR:QUAY'      => new CertaintyAssessment(I18N::translate('Quality of data')),
1720            'NOTE:CHAN:_WT_USER'          => new WebtreesUser(I18N::translate('Author of last change')),
1721            'NOTE:RESN'                   => new RestrictionNotice(I18N::translate('Restriction')),
1722            'OBJE:CHAN:_WT_USER'          => new WebtreesUser(I18N::translate('Author of last change')),
1723            'OBJE:RESN'                   => new RestrictionNotice(I18N::translate('Restriction')),
1724            'REPO:CHAN:_WT_USER'          => new WebtreesUser(I18N::translate('Author of last change')),
1725            'REPO:RESN'                   => new RestrictionNotice(I18N::translate('Restriction')),
1726            'SOUR:CHAN:_WT_USER'          => new WebtreesUser(I18N::translate('Author of last change')),
1727            'SOUR:RESN'                   => new RestrictionNotice(I18N::translate('Restriction')),
1728            'SUBM:CHAN:_WT_USER'          => new WebtreesUser(I18N::translate('Author of last change')),
1729            'SUBM:RESN'                   => new RestrictionNotice(I18N::translate('Restriction')),
1730            '_LOC:CHAN:_WT_USER'          => new WebtreesUser(I18N::translate('Author of last change')),
1731            '_LOC:RESN'                   => new RestrictionNotice(I18N::translate('Restriction')),
1732        ];
1733    }
1734
1735    /**
1736     * @return array<string,array<int,array<int,string>>>
1737     */
1738    private function webtreesSubTags(): array
1739    {
1740        return [
1741            'FAM'              => [['_UID', '0:M']],
1742            'FAM:*:SOUR'       => [['NOTE', '0:0']],
1743            'FAM:*:SOUR:DATA'  => [['TEXT', '0:1']],
1744            'FAM:ANUL'         => [['_ASSO', '0:M', 'NOTE']],
1745            'FAM:CENS'         => [['_ASSO', '0:M', 'NOTE']],
1746            'FAM:CHAN'         => [['_WT_USER', '0:1']],
1747            'FAM:DIV'          => [['_ASSO', '0:M', 'NOTE']],
1748            'FAM:DIVF'         => [['_ASSO', '0:M', 'NOTE']],
1749            'FAM:ENGA'         => [['_ASSO', '0:M', 'NOTE']],
1750            'FAM:EVEN'         => [['_ASSO', '0:M', 'NOTE']],
1751            'FAM:MARB'         => [['_ASSO', '0:M', 'NOTE']],
1752            'FAM:MARC'         => [['_ASSO', '0:M', 'NOTE']],
1753            'FAM:MARL'         => [['_ASSO', '0:M', 'NOTE']],
1754            'FAM:MARR'         => [['_ASSO', '2:M', 'NOTE']],
1755            'FAM:MARS'         => [['_ASSO', '0:M', 'NOTE']],
1756            'FAM:SLGS'         => [['_ASSO', '0:M', 'NOTE']],
1757            'FAM:SOUR:DATA'    => [['TEXT', '0:1']],
1758            'INDI'             => [['_UID', '0:M']],
1759            'INDI:*:SOUR:DATA' => [['TEXT', '0:1']],
1760            'INDI:ADOP'        => [['_ASSO', '0:M', 'NOTE']],
1761            'INDI:BAPL'        => [['_ASSO', '0:M', 'NOTE']],
1762            'INDI:BAPM'        => [['_ASSO', '2:M', 'NOTE']],
1763            'INDI:BARM'        => [['_ASSO', '0:M', 'NOTE']],
1764            'INDI:BASM'        => [['_ASSO', '0:M', 'NOTE']],
1765            'INDI:BIRT'        => [['_ASSO', '0:M', 'NOTE'], ['FAMC', '0:0']],
1766            'INDI:BURI'        => [['_ASSO', '0:M', 'NOTE']],
1767            'INDI:CENS'        => [['_ASSO', '0:M', 'NOTE']],
1768            'INDI:CHAN'        => [['_WT_USER', '0:1']],
1769            'INDI:CHR'         => [['_ASSO', '2:M', 'NOTE']],
1770            'INDI:CHRA'        => [['_ASSO', '0:M', 'NOTE']],
1771            'INDI:CONF'        => [['_ASSO', '0:M', 'NOTE']],
1772            'INDI:CONL'        => [['_ASSO', '0:M', 'NOTE']],
1773            'INDI:CREM'        => [['_ASSO', '0:M', 'NOTE']],
1774            'INDI:DEAT'        => [['_ASSO', '0:M', 'NOTE']],
1775            'INDI:EDUC'        => [['_ASSO', '0:M', 'NOTE']],
1776            'INDI:EMIG'        => [['_ASSO', '0:M', 'NOTE']],
1777            'INDI:ENDL'        => [['_ASSO', '0:M', 'NOTE']],
1778            'INDI:EVEN'        => [['_ASSO', '0:M', 'NOTE']],
1779            'INDI:GRAD'        => [['_ASSO', '0:M', 'NOTE']],
1780            'INDI:IMMI'        => [['_ASSO', '0:M', 'NOTE']],
1781            'INDI:NAME:FONE'   => [['NPFX', '0:0'], ['GIVN', '0:0'], ['SPFX', '0:0'], ['SURN', '0:0'], ['NSFX', '0:0'], ['NICK', '0:0']],
1782            'INDI:NAME:ROMN'   => [['NPFX', '0:0'], ['GIVN', '0:0'], ['SPFX', '0:0'], ['SURN', '0:0'], ['NSFX', '0:0'], ['NICK', '0:0']],
1783            'INDI:NATU'        => [['_ASSO', '0:M', 'NOTE']],
1784            'INDI:OCCU'        => [['_ASSO', '0:M', 'NOTE']],
1785            'INDI:ORDN'        => [['_ASSO', '0:M', 'NOTE']],
1786            'INDI:PROB'        => [['_ASSO', '0:M', 'NOTE']],
1787            'INDI:PROP'        => [['_ASSO', '0:M', 'NOTE']],
1788            'INDI:RESI'        => [['_ASSO', '0:M', 'NOTE']],
1789            'INDI:RETI'        => [['_ASSO', '0:M', 'NOTE']],
1790            'INDI:SLGC'        => [['_ASSO', '0:M', 'NOTE']],
1791            'INDI:SOUR:DATA'   => [['TEXT', '0:1']],
1792            'INDI:TITL'        => [['_ASSO', '0:M', 'NOTE']],
1793            'INDI:WILL'        => [['_ASSO', '0:M', 'NOTE']],
1794            'NOTE'             => [['RESN', '0:1', 'CHAN']],
1795            'NOTE:CHAN'        => [['_WT_USER', '0:1']],
1796            'NOTE:SOUR'        => [['NOTE', '0:0']],
1797            'NOTE:SOUR:DATA'   => [['TEXT', '0:1']],
1798            'OBJE'             => [['RESN', '0:1', 'CHAN'], ['_UID', '0:M']],
1799            'OBJE:CHAN'        => [['_WT_USER', '0:1']],
1800            'OBJE:SOUR'        => [['NOTE', '0:0']],
1801            'OBJE:SOUR:DATA'   => [['TEXT', '0:1']],
1802            'REPO'             => [['RESN', '0:1', 'CHAN'], ['_UID', '0:M']],
1803            'REPO:CHAN'        => [['_WT_USER', '0:1']],
1804            'SOUR'             => [['RESN', '0:1', 'CHAN'], ['_UID', '0:M']],
1805            'SOUR:CHAN'        => [['_WT_USER', '0:1']],
1806            'SUBM'             => [['RESN', '0:1', 'CHAN']],
1807            'SUBM:CHAN'        => [['_WT_USER', '0:1']],
1808        ];
1809    }
1810
1811    /**
1812     * @return array<string,array<int,array<int,string>>>
1813     */
1814    private function customSubTags(): array
1815    {
1816        $custom_family_tags     = array_filter(explode(',', Site::getPreference('CUSTOM_FAMILY_TAGS')));
1817        $custom_individual_tags = array_filter(explode(',', Site::getPreference('CUSTOM_INDIVIDUAL_TAGS')));
1818
1819        $subtags = [
1820            'FAM'  => array_map(static fn (string $tag): array => [$tag, '0:M'], $custom_family_tags),
1821            'INDI' => array_map(static fn (string $tag): array => [$tag, '0:M'], $custom_individual_tags),
1822        ];
1823
1824        if (Site::getPreference('CUSTOM_GEDCOM_L_TAGS') === '1') {
1825            $subtags['FAM'][]               = ['_ASSO', '0:M'];
1826            $subtags['FAM'][]               = ['_STAT', '0:1'];
1827            $subtags['FAM'][]               = ['_UID', '0:M'];
1828            $subtags['FAM:*:ADDR']          = [['_NAME', '0:1', 'ADR1']];
1829            $subtags['FAM:*:PLAC']          = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1830            $subtags['FAM:ENGA:PLAC']       = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1831            $subtags['FAM:MARB:PLAC']       = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1832            $subtags['FAM:MARR']            = [['_WITN', '0:M']];
1833            $subtags['FAM:MARR:PLAC']       = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1834            $subtags['FAM:SLGS:PLAC']       = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1835            $subtags['INDI'][]              = ['_UID', '0:M'];
1836            $subtags['INDI:*:ADDR']         = [['_NAME', '0:1', 'ADR1']];
1837            $subtags['INDI:*:PLAC']         = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1838            $subtags['INDI:ADOP:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1839            $subtags['INDI:BAPL:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1840            $subtags['INDI:BAPM']           = [['_GODP', '0:M'], ['_WITN', '0:M']];
1841            $subtags['INDI:BAPM:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1842            $subtags['INDI:BARM:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1843            $subtags['INDI:BASM:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1844            $subtags['INDI:BIRT:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1845            $subtags['INDI:BLES:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1846            $subtags['INDI:BURI:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1847            $subtags['INDI:CENS:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1848            $subtags['INDI:CHR']            = [['_GODP', '0:M'], ['_WITN', '0:M']];
1849            $subtags['INDI:CHR:PLAC']       = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1850            $subtags['INDI:CHRA:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1851            $subtags['INDI:CONF:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1852            $subtags['INDI:CONL:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1853            $subtags['INDI:CREM:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1854            $subtags['INDI:DEAT:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1855            $subtags['INDI:EMIG:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1856            $subtags['INDI:ENDL:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1857            $subtags['INDI:EVEN:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1858            $subtags['INDI:FCOM:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1859            $subtags['INDI:IMMI:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1860            $subtags['INDI:NAME']           = [['_RUFN', '0:1']];
1861            $subtags['INDI:NATU:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1862            $subtags['INDI:ORDN:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1863            $subtags['INDI:RESI:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1864            $subtags['INDI:SLGC:PLAC']      = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1865            $subtags['NOTE']                = [['_UID', '0:M']];
1866            $subtags['OBJE']                = [['_PRIM', '0:1:?'], ['_UID', '0:M']];
1867            $subtags['REPO']                = [['_UID', '0:M']];
1868            $subtags['REPO:ADDR']           = [['_NAME', '0:1', 'ADR1']];
1869            $subtags['SOUR']                = [['_UID', '0:M']];
1870            $subtags['SOUR:DATA:EVEN:PLAC'] = [['_POST', '0:1'], ['_MAIDENHEAD', '0:1:?'], ['_LOC', '0:1']];
1871            $subtags['SUBM']                = [['_UID', '0:M']];
1872            $subtags['SUBM:ADDR']           = [['_NAME', '0:1', 'ADR1']];
1873        }
1874
1875        return $subtags;
1876    }
1877
1878    public function registerTags(): void
1879    {
1880        // Standard GEDCOM.
1881        Registry::elementFactory()->registerTags($this->gedcom551Tags());
1882
1883        // webtrees extensions.
1884        Registry::elementFactory()->registerTags($this->webtreesTags());
1885        Registry::elementFactory()->registerSubTags($this->webtreesSubTags());
1886
1887        // Third-party extensions.
1888        Registry::elementFactory()->registerTags($this->ancestryTags());
1889        Registry::elementFactory()->registerTags($this->brothersKeeperTags());
1890        Registry::elementFactory()->registerTags($this->familySearchTags());
1891        Registry::elementFactory()->registerTags($this->familyTreeBuilderTags());
1892        Registry::elementFactory()->registerTags($this->familyTreeMakerTags());
1893        //Registry::elementFactory()->registerTags($this->gedcom53Tags());
1894        Registry::elementFactory()->registerTags($this->gedcomLTags());
1895        Registry::elementFactory()->registerTags($this->genPlusWinTags());
1896        Registry::elementFactory()->registerTags($this->legacyTags());
1897        Registry::elementFactory()->registerTags($this->personalAncestralFileTags());
1898        Registry::elementFactory()->registerTags($this->phpGedViewTags());
1899        Registry::elementFactory()->registerTags($this->rootsMagicTags());
1900        Registry::elementFactory()->registerTags($this->theMasterGenealogistTags());
1901
1902        // Creating tags from all the above are grouped into one place
1903        Registry::elementFactory()->registerSubTags($this->customSubTags());
1904    }
1905}
1906