File Coverage

File:lib/Genealogy/Relationship/Name.pm
Coverage:96.1%

linestmtbrancondsubtimecode
1package Genealogy::Relationship::Name;
2
3# Genealogy::Relationship::Name - Return the name of a genealogical relationship
4# given step counts to and from a common ancestor, the sex of person B, and a language.
5#
6# Author: Nigel Horne <njh@nigelhorne.com>
7# Licence: GPL v2
8
9
6
6
6
717068
5
73
use strict;
10
6
6
6
9
2
116
use warnings;
11
6
6
6
353
12132
14
use autodie qw(:all);
12
13
6
6
6
23261
5
152
use Carp qw(croak carp);
14
6
6
6
1765
167910
108
use Object::Configure;
15
6
6
6
15
5
109
use Params::Get;
16
6
6
6
14
50
79
use Params::Validate::Strict 0.31;
17
6
6
6
14
3
14601
use Readonly;
18
19our $VERSION = '0.03';
20
21# ---------------------------------------------------------------------------
22# Constants – relationship table keys
23# ---------------------------------------------------------------------------
24
25# Supported language codes
26Readonly::Array my @SUPPORTED_LANGUAGES => qw(de de_ch en es fa fr la);
27
28# Default language when none supplied
29Readonly::Scalar my $DEFAULT_LANGUAGE => 'en';
30
31# Sex constants
32Readonly::Scalar my $SEX_MALE   => 'M';
33Readonly::Scalar my $SEX_FEMALE => 'F';
34
35# ---------------------------------------------------------------------------
36# English relationship tables
37# Key: "$steps1,$steps2"  where steps1 = steps from A to ancestor,
38#                                steps2 = steps from B to ancestor
39# ---------------------------------------------------------------------------
40
41Readonly::Hash my %EN_MALE_RELATIONSHIPS => (
42        '0,0' => 'self',
43        '0,1' => 'son',
44        '0,2' => 'grandson',
45        '0,3' => 'great-grandson',
46        '0,4' => 'great-great-grandson',
47        '0,5' => 'great-great-great-grandson',
48        '0,6' => 'great-great-great-great-grandson',
49        '0,7' => 'great-great-great-great-great-grandson',
50        '0,8' => 'great-great-great-great-great-great-grandson',
51        '0,9' => 'great-great-great-great-great-great-great-grandson',
52        '0,10' => 'great-great-great-great-great-great-great-great-grandson',
53        '1,0' => 'father',
54        '1,1' => 'brother',
55        '1,2' => 'nephew',
56        '1,3' => 'great-nephew',
57        '1,4' => 'great-great-nephew',
58        '1,5' => 'great-great-great-nephew',
59        '1,6' => 'great-great-great-great-nephew',
60        '1,7' => 'great-great-great-great-great-nephew',
61        '1,8' => 'great-great-great-great-great-great-nephew',
62        '1,9' => 'great-great-great-great-great-great-great-nephew',
63        '1,10' => 'great-great-great-great-great-great-great-great-nephew',
64        '2,0' => 'grandfather',
65        '2,1' => 'uncle',
66        '2,2' => 'first cousin',
67        '2,3' => 'first cousin once-removed',
68        '2,4' => 'first cousin twice-removed',
69        '2,5' => 'first cousin three-times-removed',
70        '2,6' => 'first cousin four-times-removed',
71        '2,7' => 'first cousin five-times-removed',
72        '2,8' => 'first cousin six-times-removed',
73        '2,9' => 'first cousin seven-times-removed',
74        '2,10' => 'first cousin eight-times-removed',
75        '3,0' => 'great-grandfather',
76        '3,1' => 'great-uncle',
77        '3,2' => 'first cousin once-removed',
78        '3,3' => 'second cousin',
79        '3,4' => 'second cousin once-removed',
80        '3,5' => 'second cousin twice-removed',
81        '3,6' => 'second cousin three-times-removed',
82        '3,7' => 'second cousin four-times-removed',
83        '3,8' => 'second cousin five-times-removed',
84        '3,9' => 'second cousin six-times-removed',
85        '3,10' => 'second cousin seven-times-removed',
86        '4,0' => 'great-great-grandfather',
87        '4,1' => 'great-great-uncle',
88        '4,2' => 'first cousin twice-removed',
89        '4,3' => 'second cousin once-removed',
90        '4,4' => 'third cousin',
91        '4,5' => 'third cousin once-removed',
92        '4,6' => 'third cousin twice-removed',
93        '4,7' => 'third cousin three-times-removed',
94        '4,8' => 'third cousin four-times-removed',
95        '4,9' => 'third cousin five-times-removed',
96        '4,10' => 'third cousin six-times-removed',
97        '5,0' => 'great-great-great-grandfather',
98        '5,1' => 'great-great-great-uncle',
99        '5,2' => 'first cousin three-times-removed',
100        '5,3' => 'second cousin twice-removed',
101        '5,4' => 'third cousin once-removed',
102        '5,5' => 'fourth cousin',
103        '5,6' => 'fourth cousin once-removed',
104        '5,7' => 'fourth cousin twice-removed',
105        '5,8' => 'fourth cousin three-times-removed',
106        '5,9' => 'fourth cousin four-times-removed',
107        '5,10' => 'fourth cousin five-times-removed',
108        '6,0' => 'great-great-great-great-grandfather',
109        '6,1' => 'great-great-great-great-uncle',
110        '6,2' => 'first cousin four-times-removed',
111        '6,3' => 'second cousin three-times-removed',
112        '6,4' => 'third cousin twice-removed',
113        '6,5' => 'fourth cousin once-removed',
114        '6,6' => 'fifth cousin',
115        '6,7' => 'fifth cousin once-removed',
116        '6,8' => 'fifth cousin twice-removed',
117        '6,9' => 'fifth cousin three-times-removed',
118        '6,10' => 'fifth cousin four-times-removed',
119        '7,0' => 'great-great-great-great-great-grandfather',
120        '7,1' => 'great-great-great-great-great-uncle',
121        '7,2' => 'first cousin five-times-removed',
122        '7,3' => 'second cousin four-times-removed',
123        '7,4' => 'third cousin three-times-removed',
124        '7,5' => 'fourth cousin twice-removed',
125        '7,6' => 'fifth cousin once-removed',
126        '7,7' => 'sixth cousin',
127        '7,8' => 'sixth cousin once-removed',
128        '7,9' => 'sixth cousin twice-removed',
129        '7,10' => 'sixth cousin three-times-removed',
130        '8,0' => 'great-great-great-great-great-great-grandfather',
131        '8,1' => 'great-great-great-great-great-great-uncle',
132        '8,2' => 'first cousin six-times-removed',
133        '8,3' => 'second cousin five-times-removed',
134        '8,4' => 'third cousin four-times-removed',
135        '8,5' => 'fourth cousin three-times-removed',
136        '8,6' => 'fifth cousin twice-removed',
137        '8,7' => 'sixth cousin once-removed',
138        '8,8' => 'seventh cousin',
139        '8,9' => 'seventh cousin once-removed',
140        '8,10' => 'seventh cousin twice-removed',
141        '9,0' => 'great-great-great-great-great-great-great-grandfather',
142        '9,1' => 'great-great-great-great-great-great-great-uncle',
143        '9,2' => 'first cousin seven-times-removed',
144        '9,3' => 'second cousin six-times-removed',
145        '9,4' => 'third cousin five-times-removed',
146        '9,5' => 'fourth cousin four-times-removed',
147        '9,6' => 'fifth cousin three-times-removed',
148        '9,7' => 'sixth cousin twice-removed',
149        '9,8' => 'seventh cousin once-removed',
150        '9,9' => 'eighth cousin',
151        '9,10' => 'eighth cousin once-removed',
152        '10,0' => 'great-great-great-great-great-great-great-great-grandfather',
153        '10,1' => 'great-great-great-great-great-great-great-great-uncle',
154        '10,2' => 'first cousin eight-times-removed',
155        '10,3' => 'second cousin seven-times-removed',
156        '10,4' => 'third cousin six-times-removed',
157        '10,5' => 'fourth cousin five-times-removed',
158        '10,6' => 'fifth cousin four-times-removed',
159        '10,7' => 'sixth cousin three-times-removed',
160        '10,8' => 'seventh cousin twice-removed',
161        '10,9' => 'eighth cousin once-removed',
162        '10,10' => 'ninth cousin',
163        '11,1' => 'eigth great-uncle',
164        '12,1' => 'ninth great-uncle',
165        '13,1' => 'tenth great-uncle',
166        '16,1' => 'thirteenth great-uncle',
167        '17,1' => 'fourteenth great-uncle',
168);
169
170Readonly::Hash my %EN_FEMALE_RELATIONSHIPS => (
171        '0,0' => 'self',
172        '0,1' => 'daughter',
173        '0,2' => 'granddaughter',
174        '0,3' => 'great-granddaughter',
175        '0,4' => 'great-great-granddaughter',
176        '0,5' => 'great-great-great-granddaughter',
177        '0,6' => 'great-great-great-great-granddaughter',
178        '0,7' => 'great-great-great-great-great-granddaughter',
179        '0,8' => 'great-great-great-great-great-great-granddaughter',
180        '0,9' => 'great-great-great-great-great-great-great-granddaughter',
181        '0,10' => 'great-great-great-great-great-great-great-great-granddaughter',
182        '1,0' => 'mother',
183        '1,1' => 'sister',
184        '1,2' => 'niece',
185        '1,3' => 'great-niece',
186        '1,4' => 'great-great-niece',
187        '1,5' => 'great-great-great-niece',
188        '1,6' => 'great-great-great-great-niece',
189        '1,7' => 'great-great-great-great-great-niece',
190        '1,8' => 'great-great-great-great-great-great-niece',
191        '1,9' => 'great-great-great-great-great-great-great-niece',
192        '1,10' => 'great-great-great-great-great-great-great-great-niece',
193        '2,0' => 'grandmother',
194        '2,1' => 'aunt',
195        '2,2' => 'first cousin',
196        '2,3' => 'first cousin once-removed',
197        '2,4' => 'first cousin twice-removed',
198        '2,5' => 'first cousin three-times-removed',
199        '2,6' => 'first cousin four-times-removed',
200        '2,7' => 'first cousin five-times-removed',
201        '2,8' => 'first cousin six-times-removed',
202        '2,9' => 'first cousin seven-times-removed',
203        '2,10' => 'first cousin eight-times-removed',
204        '3,0' => 'great-grandmother',
205        '3,1' => 'great-aunt',
206        '3,2' => 'first cousin once-removed',
207        '3,3' => 'second cousin',
208        '3,4' => 'second cousin once-removed',
209        '3,5' => 'second cousin twice-removed',
210        '3,6' => 'second cousin three-times-removed',
211        '3,7' => 'second cousin four-times-removed',
212        '3,8' => 'second cousin five-times-removed',
213        '3,9' => 'second cousin six-times-removed',
214        '3,10' => 'second cousin seven-times-removed',
215        '4,0' => 'great-great-grandmother',
216        '4,1' => 'great-great-aunt',
217        '4,2' => 'first cousin twice-removed',
218        '4,3' => 'second cousin once-removed',
219        '4,4' => 'third cousin',
220        '4,5' => 'third cousin once-removed',
221        '4,6' => 'third cousin twice-removed',
222        '4,7' => 'third cousin three-times-removed',
223        '4,8' => 'third cousin four-times-removed',
224        '4,9' => 'third cousin five-times-removed',
225        '4,10' => 'third cousin six-times-removed',
226        '5,0' => 'great-great-great-grandmother',
227        '5,1' => 'great-great-great-aunt',
228        '5,2' => 'first cousin three-times-removed',
229        '5,3' => 'second cousin twice-removed',
230        '5,4' => 'third cousin once-removed',
231        '5,5' => 'fourth cousin',
232        '5,6' => 'fourth cousin once-removed',
233        '5,7' => 'fourth cousin twice-removed',
234        '5,8' => 'fourth cousin three-times-removed',
235        '5,9' => 'fourth cousin four-times-removed',
236        '5,10' => 'fourth cousin five-times-removed',
237        '6,0' => 'great-great-great-great-grandmother',
238        '6,1' => 'great-great-great-great-aunt',
239        '6,2' => 'first cousin four-times-removed',
240        '6,3' => 'second cousin three-times-removed',
241        '6,4' => 'third cousin twice-removed',
242        '6,5' => 'fourth cousin once-removed',
243        '6,6' => 'fifth cousin',
244        '6,7' => 'fifth cousin once-removed',
245        '6,8' => 'fifth cousin twice-removed',
246        '6,9' => 'fifth cousin three-times-removed',
247        '6,10' => 'fifth cousin four-times-removed',
248        '7,0' => 'great-great-great-great-great-grandmother',
249        '7,1' => 'great-great-great-great-great-aunt',
250        '7,2' => 'first cousin five-times-removed',
251        '7,3' => 'second cousin four-times-removed',
252        '7,4' => 'third cousin three-times-removed',
253        '7,5' => 'fourth cousin twice-removed',
254        '7,6' => 'fifth cousin once-removed',
255        '7,7' => 'sixth cousin',
256        '7,8' => 'sixth cousin once-removed',
257        '7,9' => 'sixth cousin twice-removed',
258        '7,10' => 'sixth cousin three-times-removed',
259        '8,0' => 'great-great-great-great-great-great-grandmother',
260        '8,1' => 'great-great-great-great-great-great-aunt',
261        '8,2' => 'first cousin six-times-removed',
262        '8,3' => 'second cousin five-times-removed',
263        '8,4' => 'third cousin four-times-removed',
264        '8,5' => 'fourth cousin three-times-removed',
265        '8,6' => 'fifth cousin twice-removed',
266        '8,7' => 'sixth cousin once-removed',
267        '8,8' => 'seventh cousin',
268        '8,9' => 'seventh cousin once-removed',
269        '8,10' => 'seventh cousin twice-removed',
270        '9,0' => 'great-great-great-great-great-great-great-grandmother',
271        '9,1' => 'great-great-great-great-great-great-great-aunt',
272        '9,2' => 'first cousin seven-times-removed',
273        '9,3' => 'second cousin six-times-removed',
274        '9,4' => 'third cousin five-times-removed',
275        '9,5' => 'fourth cousin four-times-removed',
276        '9,6' => 'fifth cousin three-times-removed',
277        '9,7' => 'sixth cousin twice-removed',
278        '9,8' => 'seventh cousin once-removed',
279        '9,9' => 'eighth cousin',
280        '9,10' => 'eighth cousin once-removed',
281        '10,0' => 'great-great-great-great-great-great-great-great-grandmother',
282        '10,1' => 'great-great-great-great-great-great-great-great-aunt',
283        '10,2' => 'first cousin eight-times-removed',
284        '10,3' => 'second cousin seven-times-removed',
285        '10,4' => 'third cousin six-times-removed',
286        '10,5' => 'fourth cousin five-times-removed',
287        '10,6' => 'fifth cousin four-times-removed',
288        '10,7' => 'sixth cousin three-times-removed',
289        '10,8' => 'seventh cousin twice-removed',
290        '10,9' => 'eighth cousin once-removed',
291        '10,10' => 'ninth cousin',
292        '11,1' => 'eigth great-aunt',
293        '12,1' => 'ninth great-aunt',
294        '13,1' => 'tenth great-aunt',
295        '16,1' => 'thirteenth great-aunt',
296        '17,1' => 'fourteenth great-aunt',
297);
298
299# ---------------------------------------------------------------------------
300# French relationship tables
301# ---------------------------------------------------------------------------
302
303Readonly::Hash my %FR_MALE_RELATIONSHIPS => (
304        '0,0' => 'soi-meme',
305        '0,1' => 'fils',
306        '0,2' => 'petit-fils',
307        '0,3' => 'arriere-petit-fils',
308        '0,4' => 'arriere-arriere-petit-fils',
309        '0,5' => 'arriere-arriere-arriere-petit-fils',
310        '0,6' => 'arriere-arriere-arriere-arriere-petit-fils',
311        '0,7' => 'arriere-arriere-arriere-arriere-arriere-petit-fils',
312        '0,8' => 'arriere-arriere-arriere-arriere-arriere-arriere-petit-fils',
313        '0,9' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-petit-fils',
314        '0,10' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-arriere-petit-fils',
315        '1,0' => 'pere',
316        '1,1' => "fr\N{U+00E8}re",
317        '1,2' => 'neveu',
318        '1,3' => 'grand-neveu',
319        '1,4' => 'arriere-grand-neveu',
320        '1,5' => 'arriere-arriere-grand-neveu',
321        '1,6' => 'arriere-arriere-arriere-grand-neveu',
322        '1,7' => 'arriere-arriere-arriere-arriere-grand-neveu',
323        '1,8' => 'arriere-arriere-arriere-arriere-arriere-grand-neveu',
324        '1,9' => 'arriere-arriere-arriere-arriere-arriere-arriere-grand-neveu',
325        '1,10' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-grand-neveu',
326        '2,0' => 'grand-pere',
327        '2,1' => 'oncle',
328        '2,2' => 'cousin germain',
329        '2,3' => "cousin germain \N{U+00E9}loign\N{U+00E9} au 1er degr\N{U+00E9}",
330        '2,4' => 'cousin germain deux fois eloigne',
331        '2,5' => 'cousin germain trois fois eloigne',
332        '2,6' => 'cousin germain quatre fois eloigne',
333        '2,7' => 'cousin germain cinq fois eloigne',
334        '2,8' => 'cousin germain six fois eloigne',
335        '2,9' => 'cousin germain sept fois eloigne',
336        '2,10' => 'cousin germain huit fois eloigne',
337        '3,0' => 'arriere-grand-pere',
338        '3,1' => 'grand-oncle',
339        '3,2' => 'cousin germain une fois eloigne',
340        '3,2' => "cousin germain \N{U+00E9}loign\N{U+00E9} au 1er degr\N{U+00E9}",
341        '3,3' => 'cousin issu de germain',
342        '3,4' => 'cousin issu de germain une fois eloigne',
343        '3,5' => "cousin issu de germains \N{U+00E9}loign\N{U+00E9} au 2e degr\N{U+00E9}",
344        '3,6' => 'cousin issu de germain trois fois eloigne',
345        '3,7' => 'cousin issu de germain quatre fois eloigne',
346        '3,8' => 'cousin issu de germain cinq fois eloigne',
347        '3,9' => 'cousin issu de germain six fois eloigne',
348        '3,10' => 'cousin issu de germain sept fois eloigne',
349        '4,0' => 'arriere-arriere-grand-pere',
350        '4,1' => 'arriere-grand-oncle',
351        '4,2' => 'cousin germain deux fois eloigne',
352        '4,3' => 'cousin issu de germain une fois eloigne',
353        '4,4' => 'cousin au quatrieme degre',
354        '4,5' => 'cousin au quatrieme degre une fois eloigne',
355        '4,6' => 'cousin au quatrieme degre deux fois eloigne',
356        '4,7' => "petit-cousin \N{U+00E9}loign\N{U+00E9} au 3e degr\N{U+00E9}",
357        '4,8' => 'cousin au quatrieme degre quatre fois eloigne',
358        '4,9' => 'cousin au quatrieme degre cinq fois eloigne',
359        '4,10' => 'cousin au quatrieme degre six fois eloigne',
360        '5,0' => 'arriere-arriere-arriere-grand-pere',
361        '5,1' => 'arriere-arriere-grand-oncle',
362        '5,2' => 'cousin germain trois fois eloigne',
363        '5,3' => "cousin issu de germains \N{U+00E9}loign\N{U+00E9} au 2e degr\N{U+00E9}",
364        '5,4' => 'cousin au quatrieme degre une fois eloigne',
365        '5,5' => 'cousin au cinquieme degre',
366        '5,6' => "arri\N{U+00E8}re-petit-cousin \N{U+00E9}loign\N{U+00E9} au 1er degr\N{U+00E9}",
367        '5,7' => "arri\N{U+00E8}re-petit-cousin \N{U+00E9}loign\N{U+00E9} au 2e degr\N{U+00E9}",
368        '5,8' => 'cousin au cinquieme degre trois fois eloigne',
369        '5,9' => 'cousin au cinquieme degre quatre fois eloigne',
370        '5,10' => 'cousin au cinquieme degre cinq fois eloigne',
371        '6,0' => 'arriere-arriere-arriere-arriere-grand-pere',
372        '6,1' => 'arriere-arriere-arriere-grand-oncle',
373        '6,2' => 'cousin germain quatre fois eloigne',
374        '6,3' => 'cousin issu de germain trois fois eloigne',
375        '6,4' => 'cousin au quatrieme degre deux fois eloigne',
376        '6,5' => "arri\N{U+00E8}re-petit-cousin \N{U+00E9}loign\N{U+00E9} au 1er degr\N{U+00E9}",
377        '6,6' => "arri\N{U+00E8}re-arri\N{U+00E8}re-petit-cousin",
378        '6,7' => 'cousin au sixieme degre une fois eloigne',
379        '6,8' => 'cousin au sixieme degre deux fois eloigne',
380        '6,9' => 'cousin au sixieme degre trois fois eloigne',
381        '6,10' => 'cousin au sixieme degre quatre fois eloigne',
382        '7,0' => 'arriere-arriere-arriere-arriere-arriere-grand-pere',
383        '7,1' => 'arriere-arriere-arriere-arriere-grand-oncle',
384        '7,2' => 'cousin germain cinq fois eloigne',
385        '7,3' => 'cousin issu de germain quatre fois eloigne',
386        '7,4' => "petit-cousin \N{U+00E9}loign\N{U+00E9} au 3e degr\N{U+00E9}",
387        '7,5' => "arri\N{U+00E8}re-petit-cousin \N{U+00E9}loign\N{U+00E9} au 2e degr\N{U+00E9}",
388        '7,6' => 'cousin au sixieme degre une fois eloigne',
389        '7,7' => "sixi\N{U+00E8}me cousin",
390        '7,8' => "sixi\N{U+00E8}me cousin uns fois eloinge",
391        '7,9' => 'cousin au septieme degre deux fois eloigne',
392        '7,10' => 'cousin au septieme degre trois fois eloigne',
393        '8,0' => 'arriere-arriere-arriere-arriere-arriere-arriere-grand-pere',
394        '8,1' => 'arriere-arriere-arriere-arriere-arriere-grand-oncle',
395        '8,2' => 'cousin germain six fois eloigne',
396        '8,3' => 'cousin issu de germain cinq fois eloigne',
397        '8,4' => 'cousin au quatrieme degre quatre fois eloigne',
398        '8,5' => 'cousin au cinquieme degre trois fois eloigne',
399        '8,6' => 'cousin au sixieme degre deux fois eloigne',
400        '8,7' => "sixi\N{U+00E8}me cousin uns fois eloinge",
401        '8,8' => 'cousin au huitieme degre',
402        '8,9' => 'cousin au huitieme degre une fois eloigne',
403        '8,10' => 'cousin au huitieme degre deux fois eloigne',
404        '9,0' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-grand-pere',
405        '9,1' => 'arriere-arriere-arriere-arriere-arriere-arriere-grand-oncle',
406        '9,2' => 'cousin germain sept fois eloigne',
407        '9,3' => 'cousin issu de germain six fois eloigne',
408        '9,4' => 'cousin au quatrieme degre cinq fois eloigne',
409        '9,5' => 'cousin au cinquieme degre quatre fois eloigne',
410        '9,6' => 'cousin au sixieme degre trois fois eloigne',
411        '9,7' => 'cousin au septieme degre deux fois eloigne',
412        '9,8' => 'cousin au huitieme degre une fois eloigne',
413        '9,9' => 'cousin au neuvieme degre',
414        '9,10' => 'cousin au neuvieme degre une fois eloigne',
415        '10,0' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-arriere-grand-pere',
416        '10,1' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-grand-oncle',
417        '10,2' => 'cousin germain huit fois eloigne',
418        '10,3' => 'cousin issu de germain sept fois eloigne',
419        '10,4' => 'cousin au quatrieme degre six fois eloigne',
420        '10,5' => 'cousin au cinquieme degre cinq fois eloigne',
421        '10,6' => 'cousin au sixieme degre quatre fois eloigne',
422        '10,7' => 'cousin au septieme degre trois fois eloigne',
423        '10,8' => 'cousin au huitieme degre deux fois eloigne',
424        '10,9' => 'cousin au neuvieme degre une fois eloigne',
425        '10,10' => 'cousin au dixieme degre',
426        '11,1' => "huit\N{U+0153}me grand-oncle",
427        '12,1' => "neuvi\N{U+0153}me grand-oncle",
428        '13,1' => "dixi\N{U+0153}me grand-oncle",
429);
430
431Readonly::Hash my %FR_FEMALE_RELATIONSHIPS => (
432        '0,0' => 'soi-meme',
433        '0,1' => 'fille',
434        '0,2' => 'petite-fille',
435        '0,3' => 'arriere-petite-fille',
436        '0,4' => 'arriere-arriere-petite-fille',
437        '0,5' => 'arriere-arriere-arriere-petite-fille',
438        '0,6' => 'arriere-arriere-arriere-arriere-petite-fille',
439        '0,7' => 'arriere-arriere-arriere-arriere-arriere-petite-fille',
440        '0,8' => 'arriere-arriere-arriere-arriere-arriere-arriere-petite-fille',
441        '0,9' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-petite-fille',
442        '0,10' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-arriere-petite-fille',
443        '1,0' => 'mere',
444        '1,1' => "s\N{U+0153}ur",
445        '1,2' => "ni\N{U+00E8}ce",
446        '1,3' => 'grand-niece',
447        '1,4' => 'arriere-grand-niece',
448        '1,5' => 'arriere-arriere-grand-niece',
449        '1,6' => 'arriere-arriere-arriere-grand-niece',
450        '1,7' => 'arriere-arriere-arriere-arriere-grand-niece',
451        '1,8' => 'arriere-arriere-arriere-arriere-arriere-grand-niece',
452        '1,9' => 'arriere-arriere-arriere-arriere-arriere-arriere-grand-niece',
453        '1,10' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-grand-niece',
454        '2,0' => 'grand-mere',
455        '2,1' => 'tante',
456        '2,2' => 'cousine germaine',
457        '2,3' => "cousine germaine \N{U+00E9}loign\N{U+00E9}e au 1er degr\N{U+00E9}",
458        '2,4' => 'cousine germaine deux fois eloignee',
459        '2,5' => 'cousine germaine trois fois eloignee',
460        '2,6' => 'cousine germaine quatre fois eloignee',
461        '2,7' => 'cousine germaine cinq fois eloignee',
462        '2,8' => 'cousine germaine six fois eloignee',
463        '2,9' => 'cousine germaine sept fois eloignee',
464        '2,10' => 'cousine germaine huit fois eloignee',
465        '3,0' => 'arriere-grand-mere',
466        '3,1' => 'grand-tante',
467        '3,2' => "cousine germaine \N{U+00E9}loign\N{U+00E9}e au 1er degr\N{U+00E9}",
468        '3,3' => 'cousine issue de germaine',
469        '3,4' => 'cousine issue de germaine une fois eloignee',
470        '3,5' => "cousine issue de germains \N{U+00E9}loign\N{U+00E9}e au 2e degr\N{U+00E9}",
471        '3,6' => 'cousine issue de germaine trois fois eloignee',
472        '3,7' => 'cousine issue de germaine quatre fois eloignee',
473        '3,8' => 'cousine issue de germaine cinq fois eloignee',
474        '3,9' => 'cousine issue de germaine six fois eloignee',
475        '3,10' => 'cousine issue de germaine sept fois eloignee',
476        '4,0' => 'arriere-arriere-grand-mere',
477        '4,1' => 'arriere-grand-tante',
478        '4,2' => 'cousine germaine deux fois eloignee',
479        '4,3' => 'cousine issue de germaine une fois eloignee',
480        '4,4' => 'cousine au quatrieme degre',
481        '4,5' => 'cousine au quatrieme degre une fois eloignee',
482        '4,6' => 'cousine au quatrieme degre deux fois eloignee',
483        '4,7' => "petite-cousine \N{U+00E9}loign\N{U+00E9}e au 3e degr\N{U+00E9}",
484        '4,8' => 'cousine au quatrieme degre quatre fois eloignee',
485        '4,9' => 'cousine au quatrieme degre cinq fois eloignee',
486        '4,10' => 'cousine au quatrieme degre six fois eloignee',
487        '5,0' => 'arriere-arriere-arriere-grand-mere',
488        '5,1' => 'arriere-arriere-grand-tante',
489        '5,2' => 'cousine germaine trois fois eloignee',
490        '5,3' => "cousine issue de germains \N{U+00E9}loign\N{U+00E9}e au 2e degr\N{U+00E9}",
491        '5,4' => 'cousine au quatrieme degre une fois eloignee',
492        '5,5' => 'cousine au cinquieme degre',
493        '5,6' => "arri\N{U+00E8}re-petite-cousine \N{U+00E9}loign\N{U+00E9}e au 1er degr\N{U+00E9}",
494        '5,7' => "arri\N{U+00E8}re-petite-cousine \N{U+00E9}loign\N{U+00E9}e au 2e degr\N{U+00E9}",
495        '5,8' => 'cousine au cinquieme degre trois fois eloignee',
496        '5,9' => 'cousine au cinquieme degre quatre fois eloignee',
497        '5,10' => 'cousine au cinquieme degre cinq fois eloignee',
498        '6,0' => 'arriere-arriere-arriere-arriere-grand-mere',
499        '6,1' => 'arriere-arriere-arriere-grand-tante',
500        '6,2' => 'cousine germaine quatre fois eloignee',
501        '6,3' => 'cousine issue de germaine trois fois eloignee',
502        '6,4' => 'cousine au quatrieme degre deux fois eloignee',
503        '6,6' => "arri\N{U+00E8}re-arri\N{U+00E8}re-petite-cousine",
504        '6,6' => 'cousine au sixieme degre',
505        '6,7' => 'cousine au sixieme degre une fois eloignee',
506        '6,8' => 'cousine au sixieme degre deux fois eloignee',
507        '6,9' => 'cousine au sixieme degre trois fois eloignee',
508        '6,10' => 'cousine au sixieme degre quatre fois eloignee',
509        '7,0' => 'arriere-arriere-arriere-arriere-arriere-grand-mere',
510        '7,1' => 'arriere-arriere-arriere-arriere-grand-tante',
511        '7,2' => 'cousine germaine cinq fois eloignee',
512        '7,3' => 'cousine issue de germaine quatre fois eloignee',
513        '7,4' => "petite-cousine \N{U+00E9}loign\N{U+00E9}e au 3e degr\N{U+00E9}",
514        '7,5' => "arri\N{U+00E8}re-petite-cousine \N{U+00E9}loign\N{U+00E9}e au 2e degr\N{U+00E9}",
515        '7,6' => 'cousine au sixieme degre une fois eloignee',
516        '7,7' => "sixi\N{U+00E8}me cousin",
517        '7,8' => "sixi\N{U+00E8}me cousin once-removed",
518        '7,9' => 'cousine au septieme degre deux fois eloignee',
519        '7,10' => 'cousine au septieme degre trois fois eloignee',
520        '8,0' => 'arriere-arriere-arriere-arriere-arriere-arriere-grand-mere',
521        '8,1' => 'arriere-arriere-arriere-arriere-arriere-grand-tante',
522        '8,2' => 'cousine germaine six fois eloignee',
523        '8,3' => 'cousine issue de germaine cinq fois eloignee',
524        '8,4' => 'cousine au quatrieme degre quatre fois eloignee',
525        '8,5' => 'cousine au cinquieme degre trois fois eloignee',
526        '8,6' => 'cousine au sixieme degre deux fois eloignee',
527        '8,7' => "sixi\N{U+00E8}me cousin once-removed",
528        '8,8' => 'cousine au huitieme degre',
529        '8,9' => 'cousine au huitieme degre une fois eloignee',
530        '8,10' => 'cousine au huitieme degre deux fois eloignee',
531        '9,0' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-grand-mere',
532        '9,1' => 'arriere-arriere-arriere-arriere-arriere-arriere-grand-tante',
533        '9,2' => 'cousine germaine sept fois eloignee',
534        '9,3' => 'cousine issue de germaine six fois eloignee',
535        '9,4' => 'cousine au quatrieme degre cinq fois eloignee',
536        '9,5' => 'cousine au cinquieme degre quatre fois eloignee',
537        '9,6' => 'cousine au sixieme degre trois fois eloignee',
538        '9,7' => 'cousine au septieme degre deux fois eloignee',
539        '9,8' => 'cousine au huitieme degre une fois eloignee',
540        '9,9' => 'cousine au neuvieme degre',
541        '9,10' => 'cousine au neuvieme degre une fois eloignee',
542        '10,0' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-arriere-grand-mere',
543        '10,1' => 'arriere-arriere-arriere-arriere-arriere-arriere-arriere-grand-tante',
544        '10,2' => 'cousine germaine huit fois eloignee',
545        '10,3' => 'cousine issue de germaine sept fois eloignee',
546        '10,4' => 'cousine au quatrieme degre six fois eloignee',
547        '10,5' => 'cousine au cinquieme degre cinq fois eloignee',
548        '10,6' => 'cousine au sixieme degre quatre fois eloignee',
549        '10,7' => 'cousine au septieme degre trois fois eloignee',
550        '10,8' => 'cousine au huitieme degre deux fois eloignee',
551        '10,9' => 'cousine au neuvieme degre une fois eloignee',
552        '10,10' => 'cousine au dixieme degre',
553        '11,1' => "huit\N{U+0153}me grand-tant",
554        '12,1' => "neuvi\N{U+0153}me grand-tant",
555        '13,1' => "dixi\N{U+0153}me grand-tant",
556);
557
558# ---------------------------------------------------------------------------
559# German relationship tables
560# ---------------------------------------------------------------------------
561
562Readonly::Hash my %DE_MALE_RELATIONSHIPS => (
563        '0,0' => 'sich selbst',
564        '0,1' => 'Sohn',
565        '0,2' => 'Enkel',
566        '0,3' => 'Urenkel',
567        '0,4' => 'Ururenkel',
568        '0,5' => 'Urururenkel',
569        '0,6' => 'Ururururenkel',
570        '0,7' => 'Urururururenkel',
571        '0,8' => 'Ururururururenkel',
572        '0,9' => 'Urururururururenkel',
573        '0,10' => 'Ururururururururenkel',
574        '1,0' => 'Vater',
575        '1,1' => 'Bruder',
576        '1,2' => 'Neffe',
577        '1,3' => "Gro\N{U+00DF}neffe",
578        '1,4' => 'Urgrossneffe',
579        '1,5' => 'Ururgrossneffe',
580        '1,6' => 'Urururgrossneffe',
581        '1,7' => 'Ururururgrossneffe',
582        '1,8' => 'Urururururgrossneffe',
583        '1,9' => 'Ururururururgrossneffe',
584        '1,10' => 'Urururururururgrossneffe',
585        '2,0' => "Gro\N{U+00DF}vater",
586        '2,1' => 'Onkel',
587        '2,2' => 'Cousin',
588        '2,3' => 'Cousin einmal entfernt',
589        '2,4' => 'Cousin zweimal entfernt',
590        '2,5' => 'Cousin dreimal entfernt',
591        '2,6' => 'Cousin viermal entfernt',
592        '2,7' => 'Cousin fuenfmal entfernt',
593        '2,8' => 'Cousin sechsmal entfernt',
594        '2,9' => 'Cousin siebenmal entfernt',
595        '2,10' => 'Cousin achtmal entfernt',
596        '3,0' => 'Urgrossvater',
597        '3,1' => "Gro\N{U+00DF}onkel",
598        '3,2' => 'Cousin einmal entfernt',
599        '3,3' => 'Cousin zweiten Grades',
600        '3,4' => 'Cousin zweiten Grades einmal entfernt',
601        '3,5' => 'Cousin zweiten Grades zweimal entfernt',
602        '3,6' => 'Cousin zweiten Grades dreimal entfernt',
603        '3,7' => 'Cousin zweiten Grades viermal entfernt',
604        '3,8' => 'Cousin zweiten Grades fuenfmal entfernt',
605        '3,9' => 'Cousin zweiten Grades sechsmal entfernt',
606        '3,10' => 'Cousin zweiten Grades siebenmal entfernt',
607        '4,0' => 'Ururgrossvater',
608        '4,1' => 'Urgrossonkel',
609        '4,2' => 'Cousin zweimal entfernt',
610        '4,3' => 'Cousin zweiten Grades einmal entfernt',
611        '4,4' => 'Cousin dritten Grades',
612        '4,5' => 'Cousin dritten Grades einmal entfernt',
613        '4,6' => 'Cousin dritten Grades zweimal entfernt',
614        '4,7' => 'Cousin dritten Grades dreimal entfernt',
615        '4,8' => 'Cousin dritten Grades viermal entfernt',
616        '4,9' => 'Cousin dritten Grades fuenfmal entfernt',
617        '4,10' => 'Cousin dritten Grades sechsmal entfernt',
618        '5,0' => 'Urururgrossvater',
619        '5,1' => 'Ururgrossonkel',
620        '5,2' => 'Cousin dreimal entfernt',
621        '5,3' => 'Cousin zweiten Grades zweimal entfernt',
622        '5,4' => 'Cousin dritten Grades einmal entfernt',
623        '5,5' => 'Cousin vierten Grades',
624        '5,6' => 'Cousin vierten Grades einmal entfernt',
625        '5,7' => 'Cousin vierten Grades zweimal entfernt',
626        '5,8' => 'Cousin vierten Grades dreimal entfernt',
627        '5,9' => 'Cousin vierten Grades viermal entfernt',
628        '5,10' => 'Cousin vierten Grades fuenfmal entfernt',
629        '6,0' => 'Ururururgrossvater',
630        '6,1' => 'Urururgrossonkel',
631        '6,2' => 'Cousin viermal entfernt',
632        '6,3' => 'Cousin zweiten Grades dreimal entfernt',
633        '6,4' => 'Cousin dritten Grades zweimal entfernt',
634        '6,5' => 'Cousin vierten Grades einmal entfernt',
635        '6,6' => 'Cousin fuenften Grades',
636        '6,7' => 'Cousin fuenften Grades einmal entfernt',
637        '6,8' => 'Cousin fuenften Grades zweimal entfernt',
638        '6,9' => 'Cousin fuenften Grades dreimal entfernt',
639        '6,10' => 'Cousin fuenften Grades viermal entfernt',
640        '7,0' => 'Urururururgrossvater',
641        '7,1' => 'Ururururgrossonkel',
642        '7,2' => 'Cousin fuenfmal entfernt',
643        '7,3' => 'Cousin zweiten Grades viermal entfernt',
644        '7,4' => 'Cousin dritten Grades dreimal entfernt',
645        '7,5' => 'Cousin vierten Grades zweimal entfernt',
646        '7,6' => 'Cousin fuenften Grades einmal entfernt',
647        '7,7' => 'Cousin sechsten Grades',
648        '7,8' => 'Cousin sechsten Grades einmal entfernt',
649        '7,9' => 'Cousin sechsten Grades zweimal entfernt',
650        '7,10' => 'Cousin sechsten Grades dreimal entfernt',
651        '8,0' => 'Ururururururgrossvater',
652        '8,1' => 'Urururururgrossonkel',
653        '8,2' => 'Cousin sechsmal entfernt',
654        '8,3' => 'Cousin zweiten Grades fuenfmal entfernt',
655        '8,4' => 'Cousin dritten Grades viermal entfernt',
656        '8,5' => 'Cousin vierten Grades dreimal entfernt',
657        '8,6' => 'Cousin fuenften Grades zweimal entfernt',
658        '8,7' => 'Cousin sechsten Grades einmal entfernt',
659        '8,8' => 'Cousin siebten Grades',
660        '8,9' => 'Cousin siebten Grades einmal entfernt',
661        '8,10' => 'Cousin siebten Grades zweimal entfernt',
662        '9,0' => 'Urururururururgrossvater',
663        '9,1' => 'Ururururururgrossonkel',
664        '9,2' => 'Cousin siebenmal entfernt',
665        '9,3' => 'Cousin zweiten Grades sechsmal entfernt',
666        '9,4' => 'Cousin dritten Grades fuenfmal entfernt',
667        '9,5' => 'Cousin vierten Grades viermal entfernt',
668        '9,6' => 'Cousin fuenften Grades dreimal entfernt',
669        '9,7' => 'Cousin sechsten Grades zweimal entfernt',
670        '9,8' => 'Cousin siebten Grades einmal entfernt',
671        '9,9' => 'Cousin achten Grades',
672        '9,10' => 'Cousin achten Grades einmal entfernt',
673        '10,0' => 'Ururururururururgrossvater',
674        '10,1' => 'Urururururururgrossonkel',
675        '10,2' => 'Cousin achtmal entfernt',
676        '10,3' => 'Cousin zweiten Grades siebenmal entfernt',
677        '10,4' => 'Cousin dritten Grades sechsmal entfernt',
678        '10,5' => 'Cousin vierten Grades fuenfmal entfernt',
679        '10,6' => 'Cousin fuenften Grades viermal entfernt',
680        '10,7' => 'Cousin sechsten Grades dreimal entfernt',
681        '10,8' => 'Cousin siebten Grades zweimal entfernt',
682        '10,9' => 'Cousin achten Grades einmal entfernt',
683        '10,10' => 'Cousin neunten Grades',
684        '11,1' => 'achtens grossonkel',
685        '12,1' => 'neuntens grossonkel',
686        '13,1' => 'zehntens grossonkel',
687);
688
689Readonly::Hash my %DE_FEMALE_RELATIONSHIPS => (
690        '0,0' => 'sich selbst',
691        '0,1' => 'Tochter',
692        '0,2' => 'Enkelin',
693        '0,3' => 'Urenkelin',
694        '0,4' => 'Ururenkelin',
695        '0,5' => 'Urururenkelin',
696        '0,6' => 'Ururururenkelin',
697        '0,7' => 'Urururururenkelin',
698        '0,8' => 'Ururururururenkelin',
699        '0,9' => 'Urururururururenkelin',
700        '0,10' => 'Ururururururururenkelin',
701        '1,0' => 'Mutter',
702        '1,1' => 'Schwester',
703        '1,2' => 'Nichte',
704        '1,3' => "Gro\N{U+00DF}nichte",
705        '1,4' => 'Urgrossnichte',
706        '1,5' => 'Ururgrossnichte',
707        '1,6' => 'Urururgrossnichte',
708        '1,7' => 'Ururururgrossnichte',
709        '1,8' => 'Urururururgrossnichte',
710        '1,9' => 'Ururururururgrossnichte',
711        '1,10' => 'Urururururururgrossnichte',
712        '2,0' => "Gro\N{U+00DF}mutter",
713        '2,1' => 'Tante',
714        '2,2' => 'Cousine',
715        '2,3' => 'Cousine einmal entfernt',
716        '2,4' => 'Cousine zweimal entfernt',
717        '2,5' => 'Cousine dreimal entfernt',
718        '2,6' => 'Cousine viermal entfernt',
719        '2,7' => 'Cousine fuenfmal entfernt',
720        '2,8' => 'Cousine sechsmal entfernt',
721        '2,9' => 'Cousine siebenmal entfernt',
722        '2,10' => 'Cousine achtmal entfernt',
723        '3,0' => 'Urgrossmutter',
724        '3,1' => "Gro\N{U+00DF}tante",
725        '3,2' => 'Cousine einmal entfernt',
726        '3,3' => 'Cousine zweiten Grades',
727        '3,4' => 'Cousine zweiten Grades einmal entfernt',
728        '3,5' => 'Cousine zweiten Grades zweimal entfernt',
729        '3,6' => 'Cousine zweiten Grades dreimal entfernt',
730        '3,7' => 'Cousine zweiten Grades viermal entfernt',
731        '3,8' => 'Cousine zweiten Grades fuenfmal entfernt',
732        '3,9' => 'Cousine zweiten Grades sechsmal entfernt',
733        '3,10' => 'Cousine zweiten Grades siebenmal entfernt',
734        '4,0' => 'Ururgrossmutter',
735        '4,1' => 'Urgrosstante',
736        '4,2' => 'Cousine zweimal entfernt',
737        '4,3' => 'Cousine zweiten Grades einmal entfernt',
738        '4,4' => 'Cousine dritten Grades',
739        '4,5' => 'Cousine dritten Grades einmal entfernt',
740        '4,6' => 'Cousine dritten Grades zweimal entfernt',
741        '4,7' => 'Cousine dritten Grades dreimal entfernt',
742        '4,8' => 'Cousine dritten Grades viermal entfernt',
743        '4,9' => 'Cousine dritten Grades fuenfmal entfernt',
744        '4,10' => 'Cousine dritten Grades sechsmal entfernt',
745        '5,0' => 'Urururgrossmutter',
746        '5,1' => 'Ururgrosstante',
747        '5,2' => 'Cousine dreimal entfernt',
748        '5,3' => 'Cousine zweiten Grades zweimal entfernt',
749        '5,4' => 'Cousine dritten Grades einmal entfernt',
750        '5,5' => 'Cousine vierten Grades',
751        '5,6' => 'Cousine vierten Grades einmal entfernt',
752        '5,7' => 'Cousine vierten Grades zweimal entfernt',
753        '5,8' => 'Cousine vierten Grades dreimal entfernt',
754        '5,9' => 'Cousine vierten Grades viermal entfernt',
755        '5,10' => 'Cousine vierten Grades fuenfmal entfernt',
756        '6,0' => 'Ururururgrossmutter',
757        '6,1' => 'Urururgrosstante',
758        '6,2' => 'Cousine viermal entfernt',
759        '6,3' => 'Cousine zweiten Grades dreimal entfernt',
760        '6,4' => 'Cousine dritten Grades zweimal entfernt',
761        '6,5' => 'Cousine vierten Grades einmal entfernt',
762        '6,6' => 'Cousine fuenften Grades',
763        '6,7' => 'Cousine fuenften Grades einmal entfernt',
764        '6,8' => 'Cousine fuenften Grades zweimal entfernt',
765        '6,9' => 'Cousine fuenften Grades dreimal entfernt',
766        '6,10' => 'Cousine fuenften Grades viermal entfernt',
767        '7,0' => 'Urururururgrossmutter',
768        '7,1' => 'Ururururgrosstante',
769        '7,2' => 'Cousine fuenfmal entfernt',
770        '7,3' => 'Cousine zweiten Grades viermal entfernt',
771        '7,4' => 'Cousine dritten Grades dreimal entfernt',
772        '7,5' => 'Cousine vierten Grades zweimal entfernt',
773        '7,6' => 'Cousine fuenften Grades einmal entfernt',
774        '7,7' => 'Cousine sechsten Grades',
775        '7,8' => 'Cousine sechsten Grades einmal entfernt',
776        '7,9' => 'Cousine sechsten Grades zweimal entfernt',
777        '7,10' => 'Cousine sechsten Grades dreimal entfernt',
778        '8,0' => 'Ururururururgrossmutter',
779        '8,1' => 'Urururururgrosstante',
780        '8,2' => 'Cousine sechsmal entfernt',
781        '8,3' => 'Cousine zweiten Grades fuenfmal entfernt',
782        '8,4' => 'Cousine dritten Grades viermal entfernt',
783        '8,5' => 'Cousine vierten Grades dreimal entfernt',
784        '8,6' => 'Cousine fuenften Grades zweimal entfernt',
785        '8,7' => 'Cousine sechsten Grades einmal entfernt',
786        '8,8' => 'Cousine siebten Grades',
787        '8,9' => 'Cousine siebten Grades einmal entfernt',
788        '8,10' => 'Cousine siebten Grades zweimal entfernt',
789        '9,0' => 'Urururururururgrossmutter',
790        '9,1' => 'Ururururururgrosstante',
791        '9,2' => 'Cousine siebenmal entfernt',
792        '9,3' => 'Cousine zweiten Grades sechsmal entfernt',
793        '9,4' => 'Cousine dritten Grades fuenfmal entfernt',
794        '9,5' => 'Cousine vierten Grades viermal entfernt',
795        '9,6' => 'Cousine fuenften Grades dreimal entfernt',
796        '9,7' => 'Cousine sechsten Grades zweimal entfernt',
797        '9,8' => 'Cousine siebten Grades einmal entfernt',
798        '9,9' => 'Cousine achten Grades',
799        '9,10' => 'Cousine achten Grades einmal entfernt',
800        '10,0' => 'Ururururururururgrossmutter',
801        '10,1' => 'Urururururururgrosstante',
802        '10,2' => 'Cousine achtmal entfernt',
803        '10,3' => 'Cousine zweiten Grades siebenmal entfernt',
804        '10,4' => 'Cousine dritten Grades sechsmal entfernt',
805        '10,5' => 'Cousine vierten Grades fuenfmal entfernt',
806        '10,6' => 'Cousine fuenften Grades viermal entfernt',
807        '10,7' => 'Cousine sechsten Grades dreimal entfernt',
808        '10,8' => 'Cousine siebten Grades zweimal entfernt',
809        '10,9' => 'Cousine achten Grades einmal entfernt',
810        '10,10' => 'Cousine neunten Grades',
811        '11,1' => 'achtens grosstante',
812        '12,1' => 'neuntens grosstante',
813        '13,1' => 'zehntens grosstante',
814);
815
816# ---------------------------------------------------------------------------
817# Swiss German (de-CH) relationship tables
818# Uses 'ss' instead of Eszett (\N{U+00DF}); Switzerland abolished ß in 1934
819# ---------------------------------------------------------------------------
820
821Readonly::Hash my %DE_CH_MALE_RELATIONSHIPS => (
822        '0,0' => 'sich selbst',
823        '0,1' => 'Sohn',
824        '0,2' => 'Enkel',
825        '0,3' => 'Urenkel',
826        '0,4' => 'Ururenkel',
827        '0,5' => 'Urururenkel',
828        '0,6' => 'Ururururenkel',
829        '0,7' => 'Urururururenkel',
830        '0,8' => 'Ururururururenkel',
831        '0,9' => 'Urururururururenkel',
832        '0,10' => 'Ururururururururenkel',
833        '1,0' => 'Vater',
834        '1,1' => 'Bruder',
835        '1,2' => 'Neffe',
836        '1,3' => 'Grossneffe',
837        '1,4' => 'Urgrossneffe',
838        '1,5' => 'Ururgrossneffe',
839        '1,6' => 'Urururgrossneffe',
840        '1,7' => 'Ururururgrossneffe',
841        '1,8' => 'Urururururgrossneffe',
842        '1,9' => 'Ururururururgrossneffe',
843        '1,10' => 'Urururururururgrossneffe',
844        '2,0' => 'Grossvater',
845        '2,1' => 'Onkel',
846        '2,2' => 'Cousin',
847        '2,3' => 'Cousin einmal entfernt',
848        '2,4' => 'Cousin zweimal entfernt',
849        '2,5' => 'Cousin dreimal entfernt',
850        '2,6' => 'Cousin viermal entfernt',
851        '2,7' => 'Cousin fuenfmal entfernt',
852        '2,8' => 'Cousin sechsmal entfernt',
853        '2,9' => 'Cousin siebenmal entfernt',
854        '2,10' => 'Cousin achtmal entfernt',
855        '3,0' => 'Urgrossvater',
856        '3,1' => 'Grossonkel',
857        '3,2' => 'Cousin einmal entfernt',
858        '3,3' => 'Cousin zweiten Grades',
859        '3,4' => 'Cousin zweiten Grades einmal entfernt',
860        '3,5' => 'Cousin zweiten Grades zweimal entfernt',
861        '3,6' => 'Cousin zweiten Grades dreimal entfernt',
862        '3,7' => 'Cousin zweiten Grades viermal entfernt',
863        '3,8' => 'Cousin zweiten Grades fuenfmal entfernt',
864        '3,9' => 'Cousin zweiten Grades sechsmal entfernt',
865        '3,10' => 'Cousin zweiten Grades siebenmal entfernt',
866        '4,0' => 'Ururgrossvater',
867        '4,1' => 'Urgrossonkel',
868        '4,2' => 'Cousin zweimal entfernt',
869        '4,3' => 'Cousin zweiten Grades einmal entfernt',
870        '4,4' => 'Cousin dritten Grades',
871        '4,5' => 'Cousin dritten Grades einmal entfernt',
872        '4,6' => 'Cousin dritten Grades zweimal entfernt',
873        '4,7' => 'Cousin dritten Grades dreimal entfernt',
874        '4,8' => 'Cousin dritten Grades viermal entfernt',
875        '4,9' => 'Cousin dritten Grades fuenfmal entfernt',
876        '4,10' => 'Cousin dritten Grades sechsmal entfernt',
877        '5,0' => 'Urururgrossvater',
878        '5,1' => 'Ururgrossonkel',
879        '5,2' => 'Cousin dreimal entfernt',
880        '5,3' => 'Cousin zweiten Grades zweimal entfernt',
881        '5,4' => 'Cousin dritten Grades einmal entfernt',
882        '5,5' => 'Cousin vierten Grades',
883        '5,6' => 'Cousin vierten Grades einmal entfernt',
884        '5,7' => 'Cousin vierten Grades zweimal entfernt',
885        '5,8' => 'Cousin vierten Grades dreimal entfernt',
886        '5,9' => 'Cousin vierten Grades viermal entfernt',
887        '5,10' => 'Cousin vierten Grades fuenfmal entfernt',
888        '6,0' => 'Ururururgrossvater',
889        '6,1' => 'Urururgrossonkel',
890        '6,2' => 'Cousin viermal entfernt',
891        '6,3' => 'Cousin zweiten Grades dreimal entfernt',
892        '6,4' => 'Cousin dritten Grades zweimal entfernt',
893        '6,5' => 'Cousin vierten Grades einmal entfernt',
894        '6,6' => 'Cousin fuenften Grades',
895        '6,7' => 'Cousin fuenften Grades einmal entfernt',
896        '6,8' => 'Cousin fuenften Grades zweimal entfernt',
897        '6,9' => 'Cousin fuenften Grades dreimal entfernt',
898        '6,10' => 'Cousin fuenften Grades viermal entfernt',
899        '7,0' => 'Urururururgrossvater',
900        '7,1' => 'Ururururgrossonkel',
901        '7,2' => 'Cousin fuenfmal entfernt',
902        '7,3' => 'Cousin zweiten Grades viermal entfernt',
903        '7,4' => 'Cousin dritten Grades dreimal entfernt',
904        '7,5' => 'Cousin vierten Grades zweimal entfernt',
905        '7,6' => 'Cousin fuenften Grades einmal entfernt',
906        '7,7' => 'Cousin sechsten Grades',
907        '7,8' => 'Cousin sechsten Grades einmal entfernt',
908        '7,9' => 'Cousin sechsten Grades zweimal entfernt',
909        '7,10' => 'Cousin sechsten Grades dreimal entfernt',
910        '8,0' => 'Ururururururgrossvater',
911        '8,1' => 'Urururururgrossonkel',
912        '8,2' => 'Cousin sechsmal entfernt',
913        '8,3' => 'Cousin zweiten Grades fuenfmal entfernt',
914        '8,4' => 'Cousin dritten Grades viermal entfernt',
915        '8,5' => 'Cousin vierten Grades dreimal entfernt',
916        '8,6' => 'Cousin fuenften Grades zweimal entfernt',
917        '8,7' => 'Cousin sechsten Grades einmal entfernt',
918        '8,8' => 'Cousin siebten Grades',
919        '8,9' => 'Cousin siebten Grades einmal entfernt',
920        '8,10' => 'Cousin siebten Grades zweimal entfernt',
921        '9,0' => 'Urururururururgrossvater',
922        '9,1' => 'Ururururururgrossonkel',
923        '9,2' => 'Cousin siebenmal entfernt',
924        '9,3' => 'Cousin zweiten Grades sechsmal entfernt',
925        '9,4' => 'Cousin dritten Grades fuenfmal entfernt',
926        '9,5' => 'Cousin vierten Grades viermal entfernt',
927        '9,6' => 'Cousin fuenften Grades dreimal entfernt',
928        '9,7' => 'Cousin sechsten Grades zweimal entfernt',
929        '9,8' => 'Cousin siebten Grades einmal entfernt',
930        '9,9' => 'Cousin achten Grades',
931        '9,10' => 'Cousin achten Grades einmal entfernt',
932        '10,0' => 'Ururururururururgrossvater',
933        '10,1' => 'Urururururururgrossonkel',
934        '10,2' => 'Cousin achtmal entfernt',
935        '10,3' => 'Cousin zweiten Grades siebenmal entfernt',
936        '10,4' => 'Cousin dritten Grades sechsmal entfernt',
937        '10,5' => 'Cousin vierten Grades fuenfmal entfernt',
938        '10,6' => 'Cousin fuenften Grades viermal entfernt',
939        '10,7' => 'Cousin sechsten Grades dreimal entfernt',
940        '10,8' => 'Cousin siebten Grades zweimal entfernt',
941        '10,9' => 'Cousin achten Grades einmal entfernt',
942        '10,10' => 'Cousin neunten Grades',
943        '12,1' => 'neuntens grossonkel',
944        '13,1' => 'zehntens grossonkel',
945);
946
947Readonly::Hash my %DE_CH_FEMALE_RELATIONSHIPS => (
948        '0,0' => 'sich selbst',
949        '0,1' => 'Tochter',
950        '0,2' => 'Enkelin',
951        '0,3' => 'Urenkelin',
952        '0,4' => 'Ururenkelin',
953        '0,5' => 'Urururenkelin',
954        '0,6' => 'Ururururenkelin',
955        '0,7' => 'Urururururenkelin',
956        '0,8' => 'Ururururururenkelin',
957        '0,9' => 'Urururururururenkelin',
958        '0,10' => 'Ururururururururenkelin',
959        '1,0' => 'Mutter',
960        '1,1' => 'Schwester',
961        '1,2' => 'Nichte',
962        '1,3' => 'Grossnichte',
963        '1,4' => 'Urgrossnichte',
964        '1,5' => 'Ururgrossnichte',
965        '1,6' => 'Urururgrossnichte',
966        '1,7' => 'Ururururgrossnichte',
967        '1,8' => 'Urururururgrossnichte',
968        '1,9' => 'Ururururururgrossnichte',
969        '1,10' => 'Urururururururgrossnichte',
970        '2,0' => 'Grossmutter',
971        '2,1' => 'Tante',
972        '2,2' => 'Cousine',
973        '2,3' => 'Cousine einmal entfernt',
974        '2,4' => 'Cousine zweimal entfernt',
975        '2,5' => 'Cousine dreimal entfernt',
976        '2,6' => 'Cousine viermal entfernt',
977        '2,7' => 'Cousine fuenfmal entfernt',
978        '2,8' => 'Cousine sechsmal entfernt',
979        '2,9' => 'Cousine siebenmal entfernt',
980        '2,10' => 'Cousine achtmal entfernt',
981        '3,0' => 'Urgrossmutter',
982        '3,1' => 'Grosstante',
983        '3,2' => 'Cousine einmal entfernt',
984        '3,3' => 'Cousine zweiten Grades',
985        '3,4' => 'Cousine zweiten Grades einmal entfernt',
986        '3,5' => 'Cousine zweiten Grades zweimal entfernt',
987        '3,6' => 'Cousine zweiten Grades dreimal entfernt',
988        '3,7' => 'Cousine zweiten Grades viermal entfernt',
989        '3,8' => 'Cousine zweiten Grades fuenfmal entfernt',
990        '3,9' => 'Cousine zweiten Grades sechsmal entfernt',
991        '3,10' => 'Cousine zweiten Grades siebenmal entfernt',
992        '4,0' => 'Ururgrossmutter',
993        '4,1' => 'Urgrosstante',
994        '4,2' => 'Cousine zweimal entfernt',
995        '4,3' => 'Cousine zweiten Grades einmal entfernt',
996        '4,4' => 'Cousine dritten Grades',
997        '4,5' => 'Cousine dritten Grades einmal entfernt',
998        '4,6' => 'Cousine dritten Grades zweimal entfernt',
999        '4,7' => 'Cousine dritten Grades dreimal entfernt',
1000        '4,8' => 'Cousine dritten Grades viermal entfernt',
1001        '4,9' => 'Cousine dritten Grades fuenfmal entfernt',
1002        '4,10' => 'Cousine dritten Grades sechsmal entfernt',
1003        '5,0' => 'Urururgrossmutter',
1004        '5,1' => 'Ururgrosstante',
1005        '5,2' => 'Cousine dreimal entfernt',
1006        '5,3' => 'Cousine zweiten Grades zweimal entfernt',
1007        '5,4' => 'Cousine dritten Grades einmal entfernt',
1008        '5,5' => 'Cousine vierten Grades',
1009        '5,6' => 'Cousine vierten Grades einmal entfernt',
1010        '5,7' => 'Cousine vierten Grades zweimal entfernt',
1011        '5,8' => 'Cousine vierten Grades dreimal entfernt',
1012        '5,9' => 'Cousine vierten Grades viermal entfernt',
1013        '5,10' => 'Cousine vierten Grades fuenfmal entfernt',
1014        '6,0' => 'Ururururgrossmutter',
1015        '6,1' => 'Urururgrosstante',
1016        '6,2' => 'Cousine viermal entfernt',
1017        '6,3' => 'Cousine zweiten Grades dreimal entfernt',
1018        '6,4' => 'Cousine dritten Grades zweimal entfernt',
1019        '6,5' => 'Cousine vierten Grades einmal entfernt',
1020        '6,6' => 'Cousine fuenften Grades',
1021        '6,7' => 'Cousine fuenften Grades einmal entfernt',
1022        '6,8' => 'Cousine fuenften Grades zweimal entfernt',
1023        '6,9' => 'Cousine fuenften Grades dreimal entfernt',
1024        '6,10' => 'Cousine fuenften Grades viermal entfernt',
1025        '7,0' => 'Urururururgrossmutter',
1026        '7,1' => 'Ururururgrosstante',
1027        '7,2' => 'Cousine fuenfmal entfernt',
1028        '7,3' => 'Cousine zweiten Grades viermal entfernt',
1029        '7,4' => 'Cousine dritten Grades dreimal entfernt',
1030        '7,5' => 'Cousine vierten Grades zweimal entfernt',
1031        '7,6' => 'Cousine fuenften Grades einmal entfernt',
1032        '7,7' => 'Cousine sechsten Grades',
1033        '7,8' => 'Cousine sechsten Grades einmal entfernt',
1034        '7,9' => 'Cousine sechsten Grades zweimal entfernt',
1035        '7,10' => 'Cousine sechsten Grades dreimal entfernt',
1036        '8,0' => 'Ururururururgrossmutter',
1037        '8,1' => 'Urururururgrosstante',
1038        '8,2' => 'Cousine sechsmal entfernt',
1039        '8,3' => 'Cousine zweiten Grades fuenfmal entfernt',
1040        '8,4' => 'Cousine dritten Grades viermal entfernt',
1041        '8,5' => 'Cousine vierten Grades dreimal entfernt',
1042        '8,6' => 'Cousine fuenften Grades zweimal entfernt',
1043        '8,7' => 'Cousine sechsten Grades einmal entfernt',
1044        '8,8' => 'Cousine siebten Grades',
1045        '8,9' => 'Cousine siebten Grades einmal entfernt',
1046        '8,10' => 'Cousine siebten Grades zweimal entfernt',
1047        '9,0' => 'Urururururururgrossmutter',
1048        '9,1' => 'Ururururururgrosstante',
1049        '9,2' => 'Cousine siebenmal entfernt',
1050        '9,3' => 'Cousine zweiten Grades sechsmal entfernt',
1051        '9,4' => 'Cousine dritten Grades fuenfmal entfernt',
1052        '9,5' => 'Cousine vierten Grades viermal entfernt',
1053        '9,6' => 'Cousine fuenften Grades dreimal entfernt',
1054        '9,7' => 'Cousine sechsten Grades zweimal entfernt',
1055        '9,8' => 'Cousine siebten Grades einmal entfernt',
1056        '9,9' => 'Cousine achten Grades',
1057        '9,10' => 'Cousine achten Grades einmal entfernt',
1058        '10,0' => 'Ururururururururgrossmutter',
1059        '10,1' => 'Urururururururgrosstante',
1060        '10,2' => 'Cousine achtmal entfernt',
1061        '10,3' => 'Cousine zweiten Grades siebenmal entfernt',
1062        '10,4' => 'Cousine dritten Grades sechsmal entfernt',
1063        '10,5' => 'Cousine vierten Grades fuenfmal entfernt',
1064        '10,6' => 'Cousine fuenften Grades viermal entfernt',
1065        '10,7' => 'Cousine sechsten Grades dreimal entfernt',
1066        '10,8' => 'Cousine siebten Grades zweimal entfernt',
1067        '10,9' => 'Cousine achten Grades einmal entfernt',
1068        '10,10' => 'Cousine neunten Grades',
1069        '12,1' => 'neuntens grosstant',
1070        '13,1' => 'zehntens grosstant',
1071);
1072
1073# ---------------------------------------------------------------------------
1074# Spanish relationship tables
1075# ---------------------------------------------------------------------------
1076
1077Readonly::Hash my %ES_MALE_RELATIONSHIPS => (
1078        '0,0' => 'uno mismo',
1079        '0,1' => 'hijo',
1080        '0,2' => 'nieto',
1081        '0,3' => 'bisnieto',
1082        '0,4' => 'tataranieto',
1083        '0,5' => 'chozno',
1084        '0,6' => 'bisnieto quinto',
1085        '0,7' => 'descendiente lejano',
1086        '0,8' => 'descendiente lejano',
1087        '0,9' => 'descendiente lejano',
1088        '0,10' => 'descendiente lejano',
1089        '1,0' => 'padre',
1090        '1,1' => 'hermano',
1091        '1,2' => 'sobrino',
1092        '1,3' => 'sobrino nieto',
1093        '1,4' => 'sobrino bisnieto',
1094        '1,5' => 'sobrino tataranieto',
1095        '1,6' => 'sobrino lejano',
1096        '1,7' => 'sobrino lejano',
1097        '1,8' => 'sobrino lejano',
1098        '1,9' => 'sobrino lejano',
1099        '1,10' => 'sobrino lejano',
1100        '2,0' => 'abuelo',
1101        '2,1' => 'tio',
1102        '2,2' => 'primo hermano',
1103        '2,3' => 'primo hermano una vez removido',
1104        '2,4' => 'primo hermano dos veces removido',
1105        '2,5' => 'primo hermano tres veces removido',
1106        '2,6' => 'primo hermano cuatro veces removido',
1107        '2,7' => 'primo hermano cinco veces removido',
1108        '2,8' => 'primo hermano seis veces removido',
1109        '2,9' => 'primo hermano siete veces removido',
1110        '2,10' => 'primo hermano ocho veces removido',
1111        '3,0' => 'bisabuelo',
1112        '3,1' => 'tio abuelo',
1113        '3,2' => 'primo hermano una vez removido',
1114        '3,3' => 'primo segundo',
1115        '3,4' => 'primo segundo una vez removido',
1116        '3,5' => 'primo segundo dos veces removido',
1117        '3,6' => 'primo segundo tres veces removido',
1118        '3,7' => 'primo segundo cuatro veces removido',
1119        '3,8' => 'primo segundo cinco veces removido',
1120        '3,9' => 'primo segundo seis veces removido',
1121        '3,10' => 'primo segundo siete veces removido',
1122        '4,0' => 'tatarabuelo',
1123        '4,1' => 'tio bisabuelo',
1124        '4,2' => 'primo hermano dos veces removido',
1125        '4,3' => 'primo segundo una vez removido',
1126        '4,4' => 'primo tercero',
1127        '4,5' => 'primo tercero una vez removido',
1128        '4,6' => 'primo tercero dos veces removido',
1129        '4,7' => 'primo tercero tres veces removido',
1130        '4,8' => 'primo tercero cuatro veces removido',
1131        '4,9' => 'primo tercero cinco veces removido',
1132        '4,10' => 'primo tercero seis veces removido',
1133        '5,0' => 'chozno',
1134        '5,1' => 'tio tatarabuelo',
1135        '5,2' => 'primo hermano tres veces removido',
1136        '5,3' => 'primo segundo dos veces removido',
1137        '5,4' => 'primo tercero una vez removido',
1138        '5,5' => 'primo cuarto',
1139        '5,6' => 'primo cuarto una vez removido',
1140        '5,7' => 'primo cuarto dos veces removido',
1141        '5,8' => 'primo cuarto tres veces removido',
1142        '5,9' => 'primo cuarto cuatro veces removido',
1143        '5,10' => 'primo cuarto cinco veces removido',
1144        '6,0' => 'bisabuelo quinto',
1145        '6,1' => 'tio lejano',
1146        '6,2' => 'primo hermano cuatro veces removido',
1147        '6,3' => 'primo segundo tres veces removido',
1148        '6,4' => 'primo tercero dos veces removido',
1149        '6,5' => 'primo cuarto una vez removido',
1150        '6,6' => 'primo quinto',
1151        '6,7' => 'primo quinto una vez removido',
1152        '6,8' => 'primo quinto dos veces removido',
1153        '6,9' => 'primo quinto tres veces removido',
1154        '6,10' => 'primo quinto cuatro veces removido',
1155        '7,0' => 'antepasado lejano',
1156        '7,1' => 'tio lejano',
1157        '7,2' => 'primo hermano cinco veces removido',
1158        '7,3' => 'primo segundo cuatro veces removido',
1159        '7,4' => 'primo tercero tres veces removido',
1160        '7,5' => 'primo cuarto dos veces removido',
1161        '7,6' => 'primo quinto una vez removido',
1162        '7,7' => 'primo sexto',
1163        '7,8' => 'primo sexto una vez removido',
1164        '7,9' => 'primo sexto dos veces removido',
1165        '7,10' => 'primo sexto tres veces removido',
1166        '8,0' => 'antepasado lejano',
1167        '8,1' => 'tio lejano',
1168        '8,2' => 'primo hermano seis veces removido',
1169        '8,3' => 'primo segundo cinco veces removido',
1170        '8,4' => 'primo tercero cuatro veces removido',
1171        '8,5' => 'primo cuarto tres veces removido',
1172        '8,6' => 'primo quinto dos veces removido',
1173        '8,7' => 'primo sexto una vez removido',
1174        '8,8' => 'primo septimo',
1175        '8,9' => 'primo septimo una vez removido',
1176        '8,10' => 'primo septimo dos veces removido',
1177        '9,0' => 'antepasado lejano',
1178        '9,1' => 'tio lejano',
1179        '9,2' => 'primo hermano siete veces removido',
1180        '9,3' => 'primo segundo seis veces removido',
1181        '9,4' => 'primo tercero cinco veces removido',
1182        '9,5' => 'primo cuarto cuatro veces removido',
1183        '9,6' => 'primo quinto tres veces removido',
1184        '9,7' => 'primo sexto dos veces removido',
1185        '9,8' => 'primo septimo una vez removido',
1186        '9,9' => 'primo octavo',
1187        '9,10' => 'primo octavo una vez removido',
1188        '10,0' => 'antepasado lejano',
1189        '10,1' => 'tio lejano',
1190        '10,2' => 'primo hermano ocho veces removido',
1191        '10,3' => 'primo segundo siete veces removido',
1192        '10,4' => 'primo tercero seis veces removido',
1193        '10,5' => 'primo cuarto cinco veces removido',
1194        '10,6' => 'primo quinto cuatro veces removido',
1195        '10,7' => 'primo sexto tres veces removido',
1196        '10,8' => 'primo septimo dos veces removido',
1197        '10,9' => 'primo octavo una vez removido',
1198        '10,10' => 'primo noveno',
1199);
1200
1201Readonly::Hash my %ES_FEMALE_RELATIONSHIPS => (
1202        '0,0' => 'una misma',
1203        '0,1' => 'hija',
1204        '0,2' => 'nieta',
1205        '0,3' => 'bisnieta',
1206        '0,4' => 'tataranieta',
1207        '0,5' => 'chozna',
1208        '0,6' => 'bisnieta quinta',
1209        '0,7' => 'descendiente lejana',
1210        '0,8' => 'descendiente lejana',
1211        '0,9' => 'descendiente lejana',
1212        '0,10' => 'descendiente lejana',
1213        '1,0' => 'madre',
1214        '1,1' => 'hermana',
1215        '1,2' => 'sobrina',
1216        '1,3' => 'sobrina nieta',
1217        '1,4' => 'sobrina bisnieta',
1218        '1,5' => 'sobrina tataranieta',
1219        '1,6' => 'sobrina lejana',
1220        '1,7' => 'sobrina lejana',
1221        '1,8' => 'sobrina lejana',
1222        '1,9' => 'sobrina lejana',
1223        '1,10' => 'sobrina lejana',
1224        '2,0' => 'abuela',
1225        '2,1' => 'tia',
1226        '2,2' => 'prima hermana',
1227        '2,3' => 'prima hermana una vez removida',
1228        '2,4' => 'prima hermana dos veces removida',
1229        '2,5' => 'prima hermana tres veces removida',
1230        '2,6' => 'prima hermana cuatro veces removida',
1231        '2,7' => 'prima hermana cinco veces removida',
1232        '2,8' => 'prima hermana seis veces removida',
1233        '2,9' => 'prima hermana siete veces removida',
1234        '2,10' => 'prima hermana ocho veces removida',
1235        '3,0' => 'bisabuela',
1236        '3,1' => 'tia abuela',
1237        '3,2' => 'prima hermana una vez removida',
1238        '3,3' => 'prima segunda',
1239        '3,4' => 'prima segunda una vez removida',
1240        '3,5' => 'prima segunda dos veces removida',
1241        '3,6' => 'prima segunda tres veces removida',
1242        '3,7' => 'prima segunda cuatro veces removida',
1243        '3,8' => 'prima segunda cinco veces removida',
1244        '3,9' => 'prima segunda seis veces removida',
1245        '3,10' => 'prima segunda siete veces removida',
1246        '4,0' => 'tatarabuela',
1247        '4,1' => 'tia bisabuela',
1248        '4,2' => 'prima hermana dos veces removida',
1249        '4,3' => 'prima segunda una vez removida',
1250        '4,4' => 'prima tercera',
1251        '4,5' => 'prima tercera una vez removida',
1252        '4,6' => 'prima tercera dos veces removida',
1253        '4,7' => 'prima tercera tres veces removida',
1254        '4,8' => 'prima tercera cuatro veces removida',
1255        '4,9' => 'prima tercera cinco veces removida',
1256        '4,10' => 'prima tercera seis veces removida',
1257        '5,0' => 'chozna',
1258        '5,1' => 'tia tatarabuela',
1259        '5,2' => 'prima hermana tres veces removida',
1260        '5,3' => 'prima segunda dos veces removida',
1261        '5,4' => 'prima tercera una vez removida',
1262        '5,5' => 'prima cuarta',
1263        '5,6' => 'prima cuarta una vez removida',
1264        '5,7' => 'prima cuarta dos veces removida',
1265        '5,8' => 'prima cuarta tres veces removida',
1266        '5,9' => 'prima cuarta cuatro veces removida',
1267        '5,10' => 'prima cuarta cinco veces removida',
1268        '6,0' => 'bisabuela quinta',
1269        '6,1' => 'tia lejana',
1270        '6,2' => 'prima hermana cuatro veces removida',
1271        '6,3' => 'prima segunda tres veces removida',
1272        '6,4' => 'prima tercera dos veces removida',
1273        '6,5' => 'prima cuarta una vez removida',
1274        '6,6' => 'prima quinta',
1275        '6,7' => 'prima quinta una vez removida',
1276        '6,8' => 'prima quinta dos veces removida',
1277        '6,9' => 'prima quinta tres veces removida',
1278        '6,10' => 'prima quinta cuatro veces removida',
1279        '7,0' => 'antepasada lejana',
1280        '7,1' => 'tia lejana',
1281        '7,2' => 'prima hermana cinco veces removida',
1282        '7,3' => 'prima segunda cuatro veces removida',
1283        '7,4' => 'prima tercera tres veces removida',
1284        '7,5' => 'prima cuarta dos veces removida',
1285        '7,6' => 'prima quinta una vez removida',
1286        '7,7' => 'prima sexta',
1287        '7,8' => 'prima sexta una vez removida',
1288        '7,9' => 'prima sexta dos veces removida',
1289        '7,10' => 'prima sexta tres veces removida',
1290        '8,0' => 'antepasada lejana',
1291        '8,1' => 'tia lejana',
1292        '8,2' => 'prima hermana seis veces removida',
1293        '8,3' => 'prima segunda cinco veces removida',
1294        '8,4' => 'prima tercera cuatro veces removida',
1295        '8,5' => 'prima cuarta tres veces removida',
1296        '8,6' => 'prima quinta dos veces removida',
1297        '8,7' => 'prima sexta una vez removida',
1298        '8,8' => 'prima septima',
1299        '8,9' => 'prima septima una vez removida',
1300        '8,10' => 'prima septima dos veces removida',
1301        '9,0' => 'antepasada lejana',
1302        '9,1' => 'tia lejana',
1303        '9,2' => 'prima hermana siete veces removida',
1304        '9,3' => 'prima segunda seis veces removida',
1305        '9,4' => 'prima tercera cinco veces removida',
1306        '9,5' => 'prima cuarta cuatro veces removida',
1307        '9,6' => 'prima quinta tres veces removida',
1308        '9,7' => 'prima sexta dos veces removida',
1309        '9,8' => 'prima septima una vez removida',
1310        '9,9' => 'prima octava',
1311        '9,10' => 'prima octava una vez removida',
1312        '10,0' => 'antepasada lejana',
1313        '10,1' => 'tia lejana',
1314        '10,2' => 'prima hermana ocho veces removida',
1315        '10,3' => 'prima segunda siete veces removida',
1316        '10,4' => 'prima tercera seis veces removida',
1317        '10,5' => 'prima cuarta cinco veces removida',
1318        '10,6' => 'prima quinta cuatro veces removida',
1319        '10,7' => 'prima sexta tres veces removida',
1320        '10,8' => 'prima septima dos veces removida',
1321        '10,9' => 'prima octava una vez removida',
1322        '10,10' => 'prima novena',
1323);
1324
1325# ---------------------------------------------------------------------------
1326# Farsi (Persian) relationship tables
1327# Values use \N{U+XXXX} Unicode escapes (right-to-left script)
1328# Side-specific keys: "s1,s2,paternal" / "s1,s2,maternal"
1329# ---------------------------------------------------------------------------
1330
1331Readonly::Hash my %FA_MALE_RELATIONSHIPS => (
1332        '0,0' => "\N{U+062E}\N{U+0648}\N{U+062F}",
1333        '0,1' => "\N{U+067E}\N{U+0633}\N{U+0631}",
1334        '0,2' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1335        '0,3' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1336        '0,4' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1337        '0,5' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1338        '0,6' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1339        '0,7' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1340        '0,8' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1341        '0,9' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1342        '0,10' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1343        '1,0' => "\N{U+067E}\N{U+062F}\N{U+0631}",
1344        '1,1' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}",
1345        '1,2' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1346        '1,3' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1347        '1,4' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1348        '1,5' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1349        '1,6' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1350        '1,7' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1351        '1,8' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1352        '1,9' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1353        '1,10' => "\N{U+0628}\N{U+0631}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1354        '2,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1355        '2,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1356        '2,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1357        '2,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1358        '2,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1359        '2,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1360        '2,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1361        '2,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1362        '2,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1363        '2,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1364        '2,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1365        '3,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1366        '3,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1367        '3,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1368        '3,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1369        '3,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1370        '3,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1371        '3,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1372        '3,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1373        '3,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1374        '3,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1375        '3,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1376        '4,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1377        '4,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1378        '4,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1379        '4,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1380        '4,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1381        '4,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1382        '4,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1383        '4,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1384        '4,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1385        '4,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1386        '4,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1387        '5,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1388        '5,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1389        '5,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1390        '5,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1391        '5,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1392        '5,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1393        '5,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1394        '5,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1395        '5,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1396        '5,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1397        '5,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1398        '6,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1399        '6,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1400        '6,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1401        '6,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1402        '6,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1403        '6,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1404        '6,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1405        '6,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1406        '6,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1407        '6,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1408        '6,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1409        '7,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1410        '7,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1411        '7,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1412        '7,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1413        '7,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1414        '7,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1415        '7,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1416        '7,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1417        '7,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1418        '7,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1419        '7,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1420        '8,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1421        '8,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1422        '8,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1423        '8,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1424        '8,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1425        '8,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1426        '8,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1427        '8,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1428        '8,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1429        '8,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1430        '8,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1431        '9,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1432        '9,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1433        '9,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1434        '9,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1435        '9,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1436        '9,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1437        '9,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1438        '9,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1439        '9,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1440        '9,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1441        '9,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1442        '10,0' => "\N{U+067E}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1443        '10,1' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1444        '10,2' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1445        '10,3' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1446        '10,4' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1447        '10,5' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1448        '10,6' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1449        '10,7' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1450        '10,8' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1451        '10,9' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1452        '10,10' => "\N{U+067E}\N{U+0633}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1453        '2,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1454        '2,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1455        '3,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1456        '3,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1457        '4,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1458        '4,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1459        '5,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1460        '5,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1461        '6,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1462        '6,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1463        '7,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1464        '7,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1465        '8,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1466        '8,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1467        '9,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1468        '9,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1469        '10,1,maternal' => "\N{U+062F}\N{U+0627}\N{U+06CC}\N{U+06CC}",
1470        '10,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0648}",
1471);
1472
1473Readonly::Hash my %FA_FEMALE_RELATIONSHIPS => (
1474        '0,0' => "\N{U+062E}\N{U+0648}\N{U+062F}",
1475        '0,1' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}",
1476        '0,2' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1477        '0,3' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1478        '0,4' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1479        '0,5' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1480        '0,6' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1481        '0,7' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1482        '0,8' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1483        '0,9' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1484        '0,10' => "\N{U+0646}\N{U+0648}\N{U+0647}",
1485        '1,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}",
1486        '1,1' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}",
1487        '1,2' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1488        '1,3' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1489        '1,4' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1490        '1,5' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1491        '1,6' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1492        '1,7' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1493        '1,8' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1494        '1,9' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1495        '1,10' => "\N{U+062E}\N{U+0648}\N{U+0627}\N{U+0647}\N{U+0631}\N{U+0632}\N{U+0627}\N{U+062F}\N{U+0647}",
1496        '2,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1497        '2,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1498        '2,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1499        '2,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1500        '2,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1501        '2,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1502        '2,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1503        '2,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1504        '2,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1505        '2,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1506        '2,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1507        '3,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1508        '3,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1509        '3,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1510        '3,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1511        '3,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1512        '3,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1513        '3,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1514        '3,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1515        '3,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1516        '3,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1517        '3,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1518        '4,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1519        '4,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1520        '4,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1521        '4,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1522        '4,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1523        '4,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1524        '4,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1525        '4,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1526        '4,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1527        '4,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1528        '4,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1529        '5,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1530        '5,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1531        '5,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1532        '5,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1533        '5,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1534        '5,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1535        '5,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1536        '5,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1537        '5,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1538        '5,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1539        '5,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1540        '6,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1541        '6,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1542        '6,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1543        '6,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1544        '6,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1545        '6,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1546        '6,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1547        '6,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1548        '6,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1549        '6,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1550        '6,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1551        '7,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1552        '7,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1553        '7,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1554        '7,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1555        '7,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1556        '7,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1557        '7,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1558        '7,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1559        '7,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1560        '7,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1561        '7,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1562        '8,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1563        '8,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1564        '8,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1565        '8,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1566        '8,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1567        '8,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1568        '8,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1569        '8,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1570        '8,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1571        '8,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1572        '8,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1573        '9,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1574        '9,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1575        '9,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1576        '9,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1577        '9,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1578        '9,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1579        '9,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1580        '9,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1581        '9,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1582        '9,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1583        '9,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1584        '10,0' => "\N{U+0645}\N{U+0627}\N{U+062F}\N{U+0631}\N{U+0628}\N{U+0632}\N{U+0631}\N{U+06AF}",
1585        '10,1' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1586        '10,2' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1587        '10,3' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1588        '10,4' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1589        '10,5' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1590        '10,6' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1591        '10,7' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1592        '10,8' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1593        '10,9' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1594        '10,10' => "\N{U+062F}\N{U+062E}\N{U+062A}\N{U+0631}\N{U+0639}\N{U+0645}\N{U+0648}",
1595        '2,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1596        '2,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1597        '3,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1598        '3,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1599        '4,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1600        '4,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1601        '5,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1602        '5,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1603        '6,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1604        '6,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1605        '7,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1606        '7,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1607        '8,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1608        '8,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1609        '9,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1610        '9,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1611        '10,1,maternal' => "\N{U+062E}\N{U+0627}\N{U+0644}\N{U+0647}",
1612        '10,1,paternal' => "\N{U+0639}\N{U+0645}\N{U+0647}",
1613);
1614
1615# ---------------------------------------------------------------------------
1616# Classical Latin relationship tables
1617# Many step-count combinations have no classical term; those keys are absent.
1618# Side-specific keys: "s1,s2,paternal" / "s1,s2,maternal"
1619# ---------------------------------------------------------------------------
1620
1621Readonly::Hash my %LA_MALE_RELATIONSHIPS => (
1622        '0,0' => 'ipse',
1623        '0,1' => 'filius',
1624        '0,2' => 'nepos',
1625        '0,3' => 'pronepos',
1626        '0,4' => 'abnepos',
1627        '0,5' => 'atnepos',
1628        '0,6' => 'trinepos',
1629        '1,0' => 'pater',
1630        '1,1' => 'frater',
1631        '1,2' => 'nepos',
1632        '2,0' => 'avus',
1633        '2,1' => 'patruus',
1634        '2,2' => 'consobrinus',
1635        '3,0' => 'proavus',
1636        '3,1' => 'patruus magnus',
1637        '4,0' => 'abavus',
1638        '4,1' => 'patruus maior',
1639        '5,0' => 'atavus',
1640        '5,1' => 'patruus maximus',
1641        '6,0' => 'tritavus',
1642        '2,1,maternal' => 'avunculus',
1643        '2,1,paternal' => 'patruus',
1644        '2,2,maternal' => 'consobrinus',
1645        '2,2,paternal' => 'patruelis',
1646        '3,1,maternal' => 'avunculus magnus',
1647        '3,1,paternal' => 'patruus magnus',
1648        '4,1,maternal' => 'avunculus maior',
1649        '4,1,paternal' => 'patruus maior',
1650        '5,1,maternal' => 'avunculus maximus',
1651        '5,1,paternal' => 'patruus maximus',
1652);
1653
1654Readonly::Hash my %LA_FEMALE_RELATIONSHIPS => (
1655        '0,0' => 'ipsa',
1656        '0,1' => 'filia',
1657        '0,2' => 'neptis',
1658        '0,3' => 'proneptis',
1659        '0,4' => 'abneptis',
1660        '0,5' => 'atneptis',
1661        '0,6' => 'trineptis',
1662        '1,0' => 'mater',
1663        '1,1' => 'soror',
1664        '1,2' => 'neptis',
1665        '2,0' => 'avia',
1666        '2,1' => 'amita',
1667        '2,2' => 'consobrina',
1668        '3,0' => 'proavia',
1669        '3,1' => 'amita magna',
1670        '4,0' => 'abavia',
1671        '4,1' => 'amita maior',
1672        '5,0' => 'atavia',
1673        '5,1' => 'amita maxima',
1674        '6,0' => 'tritavia',
1675        '2,1,maternal' => 'matertera',
1676        '2,1,paternal' => 'amita',
1677        '2,2,maternal' => 'consobrina',
1678        '2,2,paternal' => 'patruelis',
1679        '3,1,maternal' => 'matertera magna',
1680        '3,1,paternal' => 'amita magna',
1681        '4,1,maternal' => 'matertera maior',
1682        '4,1,paternal' => 'amita maior',
1683        '5,1,maternal' => 'matertera maxima',
1684        '5,1,paternal' => 'amita maxima',
1685);
1686
1687# ---------------------------------------------------------------------------
1688# Master dispatch table: lang -> sex -> hashref
1689# ---------------------------------------------------------------------------
1690
1691Readonly::Hash my %RELATIONSHIP_TABLES => (
1692        'en' => {
1693                $SEX_MALE   => \%EN_MALE_RELATIONSHIPS,
1694                $SEX_FEMALE => \%EN_FEMALE_RELATIONSHIPS,
1695        }, 'es' => {
1696                $SEX_MALE   => \%ES_MALE_RELATIONSHIPS,
1697                $SEX_FEMALE => \%ES_FEMALE_RELATIONSHIPS,
1698        }, 'fa' => {
1699                $SEX_MALE   => \%FA_MALE_RELATIONSHIPS,
1700                $SEX_FEMALE => \%FA_FEMALE_RELATIONSHIPS,
1701        }, 'fr' => {
1702                $SEX_MALE   => \%FR_MALE_RELATIONSHIPS,
1703                $SEX_FEMALE => \%FR_FEMALE_RELATIONSHIPS,
1704        }, 'de' => {
1705                $SEX_MALE   => \%DE_MALE_RELATIONSHIPS,
1706                $SEX_FEMALE => \%DE_FEMALE_RELATIONSHIPS,
1707        }, 'de_ch' => {
1708                $SEX_MALE   => \%DE_CH_MALE_RELATIONSHIPS,
1709                $SEX_FEMALE => \%DE_CH_FEMALE_RELATIONSHIPS,
1710        }, 'la' => {
1711                $SEX_MALE   => \%LA_MALE_RELATIONSHIPS,
1712                $SEX_FEMALE => \%LA_FEMALE_RELATIONSHIPS,
1713        },
1714);
1715# ---------------------------------------------------------------------------
1716# Constructor
1717# ---------------------------------------------------------------------------
1718
1719 - 1861
=head1 NAME

Genealogy::Relationship::Name - Return a genealogical relationship name from step counts

=head1 VERSION

Version 0.03

=head1 SYNOPSIS

    use Genealogy::Relationship::Name;

    my $namer = Genealogy::Relationship::Name->new();

    my $name = $namer->name(
        steps_to_ancestor   => 2,
        steps_from_ancestor => 3,
        sex                 => 'F',
    );
    # Returns 'first cousin once-removed'

    # With language
    my $name_fr = $namer->name(
        steps_to_ancestor   => 2,
        steps_from_ancestor => 2,
        sex                 => 'M',
        language            => 'fr',
    );
    # Returns 'cousin germain'

=head1 DESCRIPTION

C<Genealogy::Relationship::Name> maps a pair of step-counts (person A to common
ancestor, common ancestor to person B) plus the sex of person B and an optional
language code to a human-readable relationship name string.

The relationship tables were originally embedded in the C<gedcom> and C<ged2site>
distributions inside C<Gedcom::Individual::relationship_up()>; this module
extracts them into a reusable, installable CPAN distribution.

Supported languages: C<en> (English, default), C<de> (German), C<es> (Spanish),
C<fa> (Farsi/Persian), C<fr> (French), C<la> (Classical Latin).

=head1 METHODS

=head2 new

Constructor.  Creates and returns a blessed C<Genealogy::Relationship::Name>
object.

=head3 PURPOSE

Initialises the object with optional configuration: a default language for
subsequent C<name()> calls, and an optional L<Log::Abstraction> object to
use as the error logger.  Configuration may also be loaded from an INI-style
file via L<Object::Configure>.

=head3 ARGUMENTS

=over 4

=item C<language> (string, optional)

Default BCP-47 language tag (primary subtag only) for all C<name()> calls
on this object.  Supported values: C<en> (default), C<fr>, C<de>.  May be
overridden per-call by passing C<language> to C<name()>.

=item C<logger>

A pre-constructed loggining object.  When a required argument is
passed as C<undef> to C<name()>, the error is reported via
C<< $logger->error($msg) >> rather than C<croak>.  This allows
programs to route errors through their own
infrastructure with full C<ctx> context.

See L<Log::Abstraction> and the L</CONFIGURATION> section for the
recommended construction pattern.

=item C<config_file> (string, optional)

Path to an INI-style configuration file processed by L<Object::Configure>.
Any keys it sets may be overridden by arguments passed directly to C<new()>.

=back

=head3 RETURNS

A blessed C<Genealogy::Relationship::Name> object.

=head3 SIDE EFFECTS

Calls L<Object::Configure> C<configure()>, which may read from a
configuration file on disk if C<config_file> is supplied or if a default
configuration file exists for the class.

=head3 NOTES

L<Object::Configure> cannot handle object or coderef values (it treats
unknown scalar values as configuration file paths).  The C<logger> key is
therefore stashed before the C<configure()> call and restored afterward.
Any future object-valued constructor arguments must follow the same pattern.

=head3 EXAMPLE

    use Genealogy::Relationship::Name;
    use Log::Abstraction;

    # Minimal construction
    my $namer = Genealogy::Relationship::Name->new();

    # With a default language
    my $namer_fr = Genealogy::Relationship::Name->new(language => 'fr');

    # With a Log::Abstraction logger
    my $la = Log::Abstraction->new(
        logger => sub {
            my $args = shift;
            my $msg = $args->{ctx}
                ? $args->{ctx}->as_string() . ': ' . join('', @{$args->{message}})
                : join('', @{$args->{message}});
            complain({ message => $msg, person => $args->{ctx} });
        },
        ctx => $individual,
    );
    my $namer = Genealogy::Relationship::Name->new(language => 'en', logger => $la);

=head3 API SPECIFICATION

=head4 Input

    {
        language => { type => 'string', regex => qr/^(?:en|de(?:-ch)?|es|fa|fr|la)/, optional => 1 },
        logger   => { type => 'object', optional => 1 },
    }

=head4 Output

    {
        type  => 'object',
        class => 'Genealogy::Relationship::Name',
    }

=cut
1862
1863sub new {
1864        # Create and return a blessed object
1865
110
678649
        my $class = shift;
1866
1867        # Handle hash or hashref arguments
1868
110
194
        my $params = Params::Get::get_params(undef, \@_);
1869
1870        # Stash keys that are coderefs or objects before passing to Object::Configure,
1871        # which cannot handle them (it treats unknown scalar values as config file paths)
1872
110
1208
        my %stash;
1873
110
93
        for my $key (qw(logger)) {
1874
110
170
                next unless exists $params->{$key};
1875
11
16
                $stash{$key} = delete $params->{$key};
1876        }
1877
1878        # Load the configuration from a config file, if provided
1879
110
156
        $params = Object::Configure::configure($class, $params);
1880
1881        # Restore the stashed coderefs and objects after configure()
1882
110
110
307398
111
        @{$params}{keys %stash} = values %stash;
1883
1884        # Bless and return the object; logger/ctx/level keys from params
1885        # are stored directly and accessed via $self->{logger} etc.
1886        return bless {
1887                # Store any constructor-time config for Object::Configure compatibility
1888
110
110
94
370
                %{$params},
1889        }, ref($class) || $class;
1890}
1891
1892# ---------------------------------------------------------------------------
1893# Public method: name()
1894# ---------------------------------------------------------------------------
1895
1896 - 2018
=head2 name

Returns the name of the relationship between person A and person B.

=head3 PURPOSE

Given the number of steps from person A up to the nearest common ancestor
(C<steps_to_ancestor>) and the number of steps from that ancestor down to
person B (C<steps_from_ancestor>), plus the sex of person B and a language
code, returns a localised relationship-name string.

=head3 ARGUMENTS

=over 4

=item C<steps_to_ancestor> (integer, required)

Number of generational steps from person A up to the common ancestor.
Must be a non-negative integer.  Zero means person A I<is> the ancestor.

=item C<steps_from_ancestor> (integer, required)

Number of generational steps from the common ancestor down to person B.
Must be a non-negative integer.

=item C<sex> (string, required)

Sex of person B.  Must be C<'M'> (male) or C<'F'> (female).

=item C<language> (string, optional)

BCP-47-style language tag (only the primary subtag is used).
Supported values: C<en> (default), C<de>, C<es>, C<fa>, C<fr>, C<la>.

Note: C<fa> (Farsi/Persian) values are stored as C<\N{U+XXXX}> Unicode
escapes and render correctly in any Unicode-aware context.  C<la>
(Classical Latin) has a sparse table; many step-count combinations have
no classical term and return C<undef>.

=item C<person> (object, optional)

An optional person object (e.g. a C<Gedcom::Individual> instance) passed
through to the error handler when an error occurs.  Takes priority over the
C<ctx> set at construction time.  The handler receives it as C<ctx> (logger
path) or C<person> (on_error path), matching the C<complain()> interface
in C<gedcom>/C<ged2site>.

=item C<family_side> (string, optional)

C<'paternal'> or C<'maternal'>.  Used by languages that distinguish the
paternal from the maternal line for the same step counts.  Currently
relevant for:

=over 4

=item * C<la> (Latin) -- uncle/aunt (C<patruus>/C<avunculus>,
C<amita>/C<matertera>) and first cousin (C<patruelis>/C<consobrinus>)

=item * C<fa> (Farsi) -- uncle (C<amoo>/C<dayi>) and aunt
(C<ammeh>/C<khaleh>)

=back

When C<family_side> is not supplied, the table falls back to the generic
(non-side-specific) entry for that step-count pair.

=back

=head3 RETURNS

A string containing the relationship name, or C<undef> if the combination
is not found in the lookup table.

=head3 EXAMPLE

    my $namer = Genealogy::Relationship::Name->new();

    # Person A is the grandparent (2 steps up) of the common ancestor,
    # and person B is 3 steps below the ancestor; B is female => first cousin once-removed
    my $rel = $namer->name(
        steps_to_ancestor   => 2,
        steps_from_ancestor => 3,
        sex                 => 'F',
    );

=head3 API SPECIFICATION

=head4 Input

    {
        steps_to_ancestor   => { type => 'integer', minimum => 0 },
        steps_from_ancestor => { type => 'integer', minimum => 0 },
        sex                 => { type => 'string', memberof => ['M', 'F'] },
        language => { type => 'string', regex => qr/^(?:en|de(?:-ch)?|es|fa|fr|la)/, optional => 1 },
        # person is handled before validate_strict (PVS infers constraints from objects)
        family_side => { type => 'string', memberof => ['paternal','maternal'], optional => 1 },
    }

=head4 Output

    {
        type     => 'string',
        optional => 1,     # undef when the combination is not tabulated
    }

=head3 FORMAL SPECIFICATION

    name ______________________________________________________
    [In]  steps_to_ancestor   : N0
          steps_from_ancestor : N0
          sex                 : {M, F}
          language            : {en, es, fa, fr, de, la}?  (default en)
          person              : Object?
    [Out] result              : String | undef

    Let key      == steps_to_ancestor ++ "," ++ steps_from_ancestor
    Let side_key == key ++ "," ++ family_side  if family_side defined
    Let table    == RELATIONSHIP_TABLES(language)(sex)
    result == table(side_key)  if family_side defined and side_key in dom table
           == table(key)       if key in dom table
           == undef            otherwise

=cut
2019
2020sub name {
2021
1519
100743
        my $self = shift;
2022
2023        # Validate and extract the remaining parameters; capture the return value
2024
1519
1549
        my $args = Params::Validate::Strict::validate_strict(
2025                args   => Params::Get::get_params(undef, \@_) || {},
2026                schema => {
2027                        steps_to_ancestor   => { type => 'integer', minimum => 0 },
2028                        steps_from_ancestor => { type => 'integer', minimum => 0 },
2029                        sex                 => { type => 'string', memberof => ['M', 'F'] },
2030                        language => { type => 'string', regex => qr/^(?:en|de(?:-ch)?|es|fa|fr|la)/, optional => 1 },
2031                        person              => { type => 'object', optional => 1 },
2032                        family_side         => { type => 'string', memberof => ['paternal','maternal'],
2033                                                 optional => 1 },
2034                }
2035        );
2036
2037        # Extract individual parameters; undef means arg was given as undef, so
2038        # report via logger if set, otherwise croak
2039
1490
259802
        foreach my $arg(qw(steps_to_ancestor steps_from_ancestor sex)) {
2040
4457
3058
                if(!defined($args->{$arg})) {
2041
7
13
                        if(my $logger = $self->{logger}) {
2042
7
19
                                $logger->error("$arg not given");
2043                        }
2044
7
1583
                        croak("$arg not given");
2045                }
2046        }
2047
1483
805
        my $steps1 = $args->{steps_to_ancestor};
2048
1483
716
        my $steps2 = $args->{steps_from_ancestor};
2049
1483
732
        my $sex    = $args->{sex};
2050
1483
717
        my $person      = $args->{person};
2051
1483
636
        my $family_side = $args->{family_side};
2052
2053        # Fall back to constructor default or hard default if no per-call language given
2054
1483
1916
        my $lang = lc($args->{language} // $self->{language} // $DEFAULT_LANGUAGE);
2055
2056        # Swiss German (de-CH) maps to its own table before subtag stripping,
2057        # because it uses 'ss' where standard German uses Eszett
2058
1483
893
        if($lang eq 'de-ch') {
2059
7
6
                $lang = 'de_ch';
2060        } else {
2061                # Strip any region subtag (e.g. 'en-GB' -> 'en') after lowercasing
2062
1476
1108
                ($lang) = split /-/, $lang;
2063        }
2064
2065        # Build lookup key from the two step counts; try side-specific key first
2066        # for languages that distinguish paternal/maternal (Latin, Farsi)
2067
1483
891
        my $key      = "${steps1},${steps2}";
2068
1483
930
        my $side_key = defined($family_side) ? "${key},${family_side}" : undef;
2069
2070        # Retrieve the correct gender-specific table for the chosen language
2071
1483
1960
        my $table = $RELATIONSHIP_TABLES{$lang}{$sex};
2072
2073        # Prefer side-specific entry when family_side is given; fall back to generic key
2074        my $result = (defined($side_key) && exists $table->{$side_key})
2075                     ? $table->{$side_key}
2076
1483
7436
                     : $table->{$key};
2077
2078
1483
4709
        return $result;
2079}
2080
2081# ---------------------------------------------------------------------------
2082# Public method: supported_languages()
2083# ---------------------------------------------------------------------------
2084
2085 - 2120
=head2 supported_languages

Returns a sorted list of the language codes that the module supports.

=head3 PURPOSE

Allows calling code to enumerate the languages available for C<name()>
without hard-coding them.

=head3 ARGUMENTS

None.

=head3 RETURNS

A list (or array-ref in scalar context) of language code strings,
currently C<('de', 'de_ch', 'en', 'es', 'fa', 'fr', 'la')>.

=head3 EXAMPLE

    my @langs = $namer->supported_languages();
    # ( 'de', 'de_ch', 'en', 'es', 'fa', 'fr', 'la' )

=head3 API SPECIFICATION

=head4 Input

    {}   # no arguments

=head4 Output

    {
        type => ARRAYREF,   # sorted list of language codes
    }

=cut
2121
2122sub supported_languages {
2123        # Return the sorted set of keys from the master dispatch table
2124
11
1077
        my @langs = sort keys %RELATIONSHIP_TABLES;
2125
11
224
        return wantarray ? @langs : \@langs;
2126}
2127
2128# ---------------------------------------------------------------------------
2129# Public method: known_sexes()
2130# ---------------------------------------------------------------------------
2131
2132 - 2170
=head2 known_sexes

Returns the list of sex codes accepted by C<name()>.

=head3 PURPOSE

Documents and exposes the set of valid C<sex> values so that callers can
validate their own input without duplicating knowledge.

=head3 ARGUMENTS

None.

=head3 RETURNS

A list (or array-ref in scalar context) of valid sex code strings: C<('F', 'M')>.

=head3 SIDE EFFECTS

None.

=head3 EXAMPLE

    my @sexes = $namer->known_sexes();
    # ( 'F', 'M' )

=head3 API SPECIFICATION

=head4 Input

    {}   # no arguments

=head4 Output

    {
        type => ARRAYREF,
    }

=cut
2171
2172sub known_sexes {
2173        # Return the two valid sex codes in sorted order
2174
10
955
        my @sexes = sort($SEX_FEMALE, $SEX_MALE);
2175
10
19
        return wantarray ? @sexes : \@sexes;
2176}
2177
21781;
2179