Passed
Push — main ( 3b30be...b9a9ff )
by Greg
06:04
created

Gedcom::heredis()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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