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