1 /** Generic Language Constructs.
2     See_Also: https://en.wikipedia.org/wiki/Predicate_(grammar)
3 
4     Note that ! and ? are more definite sentence enders than .
5 
6     TODO `isSomeString` => `isStringLike`
7 
8     TODO Use static foreach to add declarations for all isX, for each X
9 
10     See_Also: http://forum.dlang.org/thread/mgdtuxkuswfxxoithwxh@forum.dlang.org
11 */
12 module nxt.lingua;
13 
14 import std.traits : isSomeChar, isSomeString;
15 import std.algorithm.comparison : among;
16 import std.algorithm.iteration : uniq;
17 import std.array : array;
18 import std.conv;
19 
20 // TODO add overload to std.algorithm.among that takes an immutable array as
21 // argument to prevent calls to aliasSeqOf
22 import std.meta : aliasSeqOf;
23 
24 import nxt.languages: Lang;
25 
26 @safe pure:
27 
28 /** Computer Token Usage. */
29 enum Usage
30 {
31     unknown,
32     definition,
33     reference,
34     call
35 }
36 
37 /// ================ English Articles
38 
39 /** English indefinite articles. */
40 static immutable englishIndefiniteArticles = [`a`, `an`];
41 
42 /** English definite articles. */
43 static immutable englishDefiniteArticles = [`the`];
44 
45 /** English definite articles. */
46 static immutable englishArticles = englishIndefiniteArticles ~ englishDefiniteArticles;
47 
48 bool isEnglishIndefiniteArticle(S)(S s)
49 {
50     return cast(bool)s.among!(aliasSeqOf!englishIndefiniteArticles);
51 }
52 
53 bool isEnglishDefiniteArticle(S)(S s)
54 if (isSomeString!S)
55 {
56     return cast(bool)s.among!(aliasSeqOf!englishDefiniteArticles);
57 }
58 
59 bool isEnglishArticle(S)(S s)
60 if (isSomeString!S)
61 {
62     return cast(bool)s.among!(aliasSeqOf!englishArticles);
63 }
64 
65 /// ================ German Articles
66 
67 /** German indefinite articles. */
68 static immutable germanIndefiniteArticles = [`ein`, `eine`, `einer`, `einen`, `einem`, `eines`];
69 
70 /** German definite articles. */
71 static immutable germanDefiniteArticles = [`der`, `die`, `das`, `den`, `dem`, `des`];
72 
73 /** German definite articles. */
74 static immutable germanArticles = germanIndefiniteArticles ~ germanDefiniteArticles;
75 
76 /** Check if $(D s) is a Vowel. */
77 bool isGermanIndefiniteArticle(S)(S s)
78 if (isSomeString!S)
79 {
80     return cast(bool)s.among!(aliasSeqOf!germanIndefiniteArticles);
81 }
82 
83 /** Check if $(D s) is a Vowel. */
84 bool isGermanDefiniteArticle(S)(S s)
85 if (isSomeString!S)
86 {
87     return cast(bool)s.among!(aliasSeqOf!germanDefiniteArticles);
88 }
89 
90 /** Check if $(D s) is a Vowel. */
91 bool isGermanArticle(S)(S s)
92 if (isSomeString!C)
93 {
94     return cast(bool)s.among!(aliasSeqOf!germanArticles);
95 }
96 
97 /// ================ Vowels
98 
99 /** English vowel type.
100  * See_Also: https://simple.wikipedia.org/wiki/Vowel
101  */
102 enum EnglishVowel { a, o, u, e, i, y,
103                     A, O, U, E, I, Y }
104 
105 /** English Vowels. */
106 static immutable dchar[] englishVowels = ['a', 'o', 'u', 'e', 'i', 'y',
107                                           'A', 'O', 'U', 'E', 'I', 'Y'];
108 
109 /** Check if `c` is a Vowel. */
110 bool isEnglishVowel(const dchar c) nothrow @nogc
111 {
112     return cast(bool)c.among!(aliasSeqOf!englishVowels);
113 }
114 
115 /** English Accented Vowels. */
116 static immutable dchar[] englishAccentedVowels = ['é'];
117 
118 /** Check if `c` is an Accented Vowel. */
119 bool isEnglishAccentedVowel(const dchar c) nothrow @nogc
120 {
121     return cast(bool)c.among!(aliasSeqOf!englishAccentedVowels);
122 }
123 
124 nothrow @nogc unittest
125 {
126     assert('é'.isEnglishAccentedVowel);
127 }
128 
129 /** Swedish Hard Vowels. */
130 static immutable swedishHardVowels = ['a', 'o', 'u', 'å',
131                                'A', 'O', 'U', 'Å'];
132 
133 /** Swedish Soft Vowels. */
134 static immutable swedishSoftVowels = ['e', 'i', 'y', 'ä', 'ö',
135                                'E', 'I', 'Y', 'Ä', 'Ö'];
136 
137 /** Swedish Vowels. */
138 static immutable swedishVowels = swedishHardVowels ~ swedishSoftVowels;
139 
140 /** Check if `c` is a Swedish Vowel. */
141 bool isSwedishVowel(const dchar c) nothrow @nogc
142 {
143     return cast(bool)c.among!(aliasSeqOf!swedishVowels);
144 }
145 
146 /** Check if `c` is a Swedish hard vowel. */
147 bool isSwedishHardVowel(const dchar c) nothrow @nogc
148 {
149     return cast(bool)c.among!(aliasSeqOf!swedishHardVowels);
150 }
151 
152 /** Check if `c` is a Swedish soft vowel. */
153 bool isSwedishSoftVowel(const dchar c) nothrow @nogc
154 {
155     return cast(bool)c.among!(aliasSeqOf!swedishSoftVowels);
156 }
157 
158 /** Spanish Accented Vowels. */
159 enum spanishAccentedVowels = ['á', 'é', 'í', 'ó', 'ú',
160                               'Á', 'É', 'Í', 'Ó', 'Ú'];
161 
162 /** Check if `c` is a Spanish Accented Vowel. */
163 bool isSpanishAccentedVowel(const dchar c) nothrow @nogc
164 {
165     return cast(bool)c.among!(aliasSeqOf!spanishAccentedVowels);
166 }
167 
168 /** Check if `c` is a Spanish Vowel. */
169 bool isSpanishVowel(const dchar c) nothrow @nogc
170 {
171     return (c.isEnglishVowel ||
172             c.isSpanishAccentedVowel);
173 }
174 
175 nothrow @nogc unittest
176 {
177     assert('é'.isSpanishVowel);
178 }
179 
180 /** Check if `c` is a Vowel in language $(D lang). */
181 bool isVowel(const dchar c, Lang lang) nothrow @nogc
182 {
183     switch (lang)
184     {
185     case Lang.en: return c.isEnglishVowel;
186     case Lang.sv: return c.isSwedishVowel;
187     default: return c.isEnglishVowel;
188     }
189 }
190 
191 nothrow @nogc unittest
192 {
193     assert(!'k'.isSwedishVowel);
194     assert('å'.isSwedishVowel);
195 }
196 
197 /** English consonant type.
198  * See_Also: https://simple.wikipedia.org/wiki/Consonant
199  */
200 enum EnglishConsonant { b, c, d, f, g, h, j, k, l, m, n, p, q, r, s, t, v, w, x }
201 
202 /** English lowercase consontant characters. */
203 static immutable dchar[] englishLowerConsonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x'];
204 
205 /** English uppercase consontant characters. */
206 static immutable dchar[] englishUpperConsonants = ['B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X'];
207 
208 /** English consontant characters. */
209 static immutable dchar[] englishConsonants = englishLowerConsonants ~ englishUpperConsonants;
210 
211 /** Check if `c` is a Consonant. */
212 bool isEnglishConsonant(const dchar c) nothrow @nogc
213 {
214     return cast(bool)c.among!(aliasSeqOf!englishConsonants);
215 }
216 alias isSwedishConsonant = isEnglishConsonant;
217 
218 nothrow @nogc unittest
219 {
220     assert('k'.isEnglishConsonant);
221     assert(!'å'.isEnglishConsonant);
222 }
223 
224 /** English letters. */
225 static immutable dchar[] englishLetters = englishVowels ~ englishConsonants;
226 
227 /** Check if `c` is a letter. */
228 bool isEnglishLetter(const dchar c) nothrow @nogc
229 {
230     return cast(bool)c.among!(aliasSeqOf!englishLetters);
231 }
232 alias isEnglish = isEnglishLetter;
233 
234 nothrow @nogc unittest
235 {
236     assert('k'.isEnglishLetter);
237     assert(!'å'.isEnglishLetter);
238 }
239 
240 static immutable englishDoubleConsonants = [`bb`, `dd`, `ff`, `gg`, `mm`, `nn`, `pp`, `rr`, `tt`, `ck`, `ft`];
241 
242 /** Check if `s` is an English Double consonant. */
243 bool isEnglishDoubleConsonant(scope const(char)[] s) nothrow @nogc
244 {
245     return cast(bool)s.among!(`bb`, `dd`, `ff`, `gg`, `mm`, `nn`, `pp`, `rr`, `tt`, `ck`, `ft`);
246 }
247 
248 /** Computer token. */
249 enum TokenId
250 {
251     unknown,
252 
253     keyword,
254     type,
255     constant,
256     comment,
257     variableName,
258     functionName,
259     builtinName,
260     templateName,
261     macroName,
262     aliasName,
263     enumeration,
264     enumerator,
265     constructor,
266     destructors,
267     operator,
268 }
269 
270 /** Swedish Verb Inflection (conjugation of a verb).
271  *
272  * See_Also: http://www.101languages.net/swedish/swedish-verb-conjugator/
273  * See_Also: http://www.verbix.com/webverbix/Swedish/springa.html
274  */
275 enum SwedishVerbInflection
276 {
277     unknown,
278 }
279 
280 /** Verb Form.
281  *
282  * See_Also: http://verb.woxikon.se/sv/springa
283  */
284 enum VerbForm
285 {
286     unknown,
287 
288     imperative,                 // Swedish example: spring
289 
290     infinitive,                 // sv:infinitiv,grundform. Swedish example: springa
291     base = infinitive,
292 
293     presentIndicative,          // sv:presens. Swedish example: springer
294 
295     presentParticiple,          // sv:presens particip. Swedish example: springande
296     gerund = presentParticiple, // Form that functions as a noun. Source: https://en.wikipedia.org/wiki/Gerund
297 
298     pastIndicative,             // sv:imperfekt. Swedish example: sprang
299     preteritum = pastIndicative,
300 
301     supinum,                    // Swedish example: sprungit
302     pastParticiple = supinum,
303 
304     perfekt,                    // sv:perfekt. Swedish example: har sprungit
305 
306     perfektParticiple,          // sv:perfekt particip. Swedish example: sprungen
307 
308     pluskvamperfekt,            // sv:pluskvamperfekt. Swedish example: hade sprungit
309 
310     futurum,                    // Swedish example:ska springa
311 
312     futurumExaktum,             // Swedish example:ska ha sprungit
313     futurumPerfect = futurumExaktum,
314 
315     konditionalisI,             // Swedish example:skulle springa
316 
317     conditionalPerfect,         // Swedish example:skulle ha sprungit
318     konditionalisII = conditionalPerfect,
319 }
320 
321 /** Verb Instance. */
322 struct Verb(S)
323 if (isSomeString!S)
324 {
325     S expr;
326     VerbForm form;
327     alias expr this;
328 }
329 
330 /** Subject Count. */
331 enum Count
332 {
333     unknown,
334     singular,
335     plural,
336     uncountable
337 }
338 
339 struct Noun(S)
340 if (isSomeString!S)
341 {
342     S expr;
343     Count count;
344     alias expr this;
345 }
346 
347 /** Comparation.
348  * See_Also: https://en.wikipedia.org/wiki/Comparison_(grammar)
349  */
350 enum Comparation
351 {
352     unknown,
353     positive,
354     comparative,
355     superlative,
356     elative,
357     exzessive
358 }
359 
360 struct Adjective(S)
361 if (isSomeString!S)
362 {
363     S expr;
364     Comparation comparation;
365     alias expr this;
366 }
367 
368 /** English Tense.
369  *
370  * Same as "tempus" in Swedish.
371  *
372  * See_Also: http://www.ego4u.com/en/cram-up/grammar/tenses-graphic
373  * See_Also: http://www.ego4u.com/en/cram-up/grammar/tenses-examples
374  */
375 enum Tense
376 {
377     unknown,
378 
379     present, presens = present, // sv:nutid
380     past, preteritum = past, imperfekt = past, // sv:dåtid, https://en.wikipedia.org/wiki/Past_tense
381     future, futurum = future, // framtid, https://en.wikipedia.org/wiki/Future_tense
382 
383     pastMoment,
384     presentMoment, // sv:plays
385     futureMoment, // [will|is going to|intends to] play
386 
387     pastPeriod,
388     presentPeriod,
389     futurePeriod,
390 
391     pastResult,
392     presentResult,
393     futureResult,
394 
395     pastDuration,
396     presentDuration,
397     futureDuration,
398 }
399 alias Tempus = Tense;
400 
401 nothrow @nogc
402 {
403     bool isPast(Tense tense)
404     {
405         with (Tense)
406             return cast(bool)tense.among!(past, pastMoment, pastPeriod, pastResult, pastDuration);
407     }
408 
409     bool isPresent(Tense tense)
410     {
411         with (Tense)
412             return cast(bool)tense.among!(present, presentMoment, presentPeriod, presentResult, presentDuration);
413     }
414 
415     bool isFuture(Tense tense)
416     {
417         with (Tense)
418             return cast(bool)tense.among!(future, futureMoment, futurePeriod, futureResult, futureDuration);
419     }
420 }
421 
422 /** Part of a Sentence. */
423 enum SentencePart
424 {
425     unknown,
426     subject,
427     predicate,
428     adverbial,
429     object,
430 }
431 
432 enum Adverbial
433 {
434     unknown,
435 
436     manner,          // they were playing `happily` (sätts-adverbial in Swedish)
437 
438     place,                      // we met in `London`, `at the beach`
439     space = place,
440 
441     time,                       // they start work `at six thirty`
442 
443     probability,                // `perhaps` the weather will be fine
444 
445     direction, // superman flew `in`, the car drove `out` (förändring av tillstånd in Swedish)
446     location,  // are you `in`?, the ball is `out` (oföränderligt tillstånd in Swedish)
447 
448     quantifier,                 // he weighs `63 kilograms` (måtts-adverbial in Swedish)
449 
450     comparation,                // (grads-adverbial in Swedish)
451 
452     cause,                      // (orsaks-adverbial in Swedish)
453 
454     circumstance,               // (omständighets-adverbial in Swedish)
455 }
456 
457 class Part
458 {
459 }
460 
461 // class Predicate : Part
462 // {
463 // }
464 
465 /** Article (of noun).
466  *
467  * See_Also: https://en.wikipedia.org/wiki/Article_(grammar)
468  */
469 enum Article
470 {
471     unknown,                    ///< Unknown.
472     definite, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Definite_article
473     indefinite, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Indefinite_article
474     proper,     ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Proper_article
475     partitive, ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Partitive_article.
476     negative,  ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Negative_article
477     zero,      ///< See_Also: https://en.wikipedia.org/wiki/Article_(grammar)#Zero_article
478 }
479 
480 class Subject : Part
481 {
482     Article article;
483 }
484 
485 static immutable implies = [`in order to`];
486 
487 /** Subject Person. */
488 enum Person
489 {
490     unknown,
491     first,
492     second,
493     third
494 }
495 
496 /** Grammatical Gender.
497  *
498  * Called genus in Swedish.
499  *
500  * See_Also: https://en.wikipedia.org/wiki/Grammatical_gender
501  * See_Also: https://sv.wikipedia.org/wiki/Genus_(k%C3%B6nsbegrepp)
502  */
503 enum Gender
504 {
505     unknown,
506 
507     male, masculine = male,    // maskulinum
508 
509     female, feminine = female, // femininum
510 
511     neutral, neuter = neutral, neutrum = neuter, // non-alive. for example: "något"
512 
513     common, utrum = common, reale = utrum, // Present in Swedish. real/alive. for example: "någon"
514 }
515 
516 /** (Grammatical) Mood.
517  *
518  * Sometimes also called mode.
519  *
520  * Named modus in Swedish.
521  *
522  * See_Also: https://en.wikipedia.org/wiki/Grammatical_mood
523  * See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#mood
524  */
525 enum Mood
526 {
527     unknown,
528 
529     indicative, // indikativ in Swedish. Example: I eat pizza.
530 
531     /// See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#subjunctive
532     subjunctive,          // Example: if I were to eat more pizza, I would be sick.
533     conjunctive = subjunctive, // konjunktiv in Swedish
534 
535     conditional,
536     optative,
537 
538     /// See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#imperative
539     imperative, // imperativ in Swedish. Example: eat the pizza!
540 
541     jussive,
542     potential,
543     inferential,
544     interrogative,
545 
546     /// See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#wh-question
547     whQuestion, // Example: who is eating pizza?
548 
549     /// See_Also: https://www.cse.unsw.edu.au/~billw/nlpdict.html#yn-question
550     ynQuestion, // Example: did you eat pizza?
551 }
552 
553 /** Check if $(D mood) is a Realis Mood.
554  *
555  * See_Also: https://en.wikipedia.org/wiki/Grammatical_mood#Realis_moods
556  */
557 bool isRealis(Mood mood) @nogc nothrow
558 {
559     with (Mood)
560     {
561         return cast(bool)mood.among!(indicative);
562     }
563 }
564 
565 enum realisMoods = [Mood.indicative];
566 
567 /** Check if $(D mood) is a Irrealis Mood.
568  *
569  * See_Also: https://en.wikipedia.org/wiki/Grammatical_mood#Irrealis_moods
570  */
571 bool isIrrealis(Mood mood) @nogc nothrow
572 {
573     with (Mood)
574     {
575         return cast(bool)mood.among!(subjunctive,
576                                      conditional,
577                                      optative,
578                                      imperative,
579                                      jussive,
580                                      potential,
581                                      inferential);
582     }
583 }
584 
585 enum irrealisMoods = [Mood.subjunctive,
586                       Mood.conditional,
587                       Mood.optative,
588                       Mood.imperative,
589                       Mood.jussive,
590                       Mood.potential,
591                       Mood.inferential];
592 
593 /** English Negation Prefixes.
594  *
595  * See_Also: http://www.english-for-students.com/Negative-Prefixes.html
596  */
597 static immutable englishNegationPrefixes = [ `un`, `non`, `dis`, `im`, `in`, `il`, `ir`, ];
598 
599 static immutable swedishNegationPrefixes = [ `icke`, `o`, ];
600 
601 /** English Noun Suffixes.
602  *
603  * See_Also: http://www.english-for-students.com/Noun-Suffixes.html
604  */
605 static immutable adjectiveNounSuffixes = [ `ness`, `ity`, `ment`, `ance` ];
606 static immutable verbNounSuffixes = [ `tion`, `sion`, `ment`, `ence` ];
607 static immutable nounNounSuffixes = [ `ship`, `hood` ];
608 static immutable allNounSuffixes = (adjectiveNounSuffixes ~
609                                     verbNounSuffixes ~
610                                     nounNounSuffixes ~
611                                     [ `s`, `ses`, `xes`, `zes`, `ches`, `shes`, `men`, `ies`, ]);
612 
613 /** English Verb Suffixes. */
614 static immutable verbSuffixes = [ `s`, `ies`, `es`, `es`, `ed`, `ed`, `ing`, `ing`, ];
615 
616 /** English Adjective Suffixes. */
617 static immutable adjectiveSuffixes = [ `er`, `est`, `er`, `est` ];
618 
619 /** English Job/Professin Title Suffixes.
620  *
621  * Typically built from noun or verb bases.
622  *
623  * See_Also: http://www.english-for-students.com/Job-Title-Suffixes.html
624  */
625 static immutable jobTitleSuffixes = [ `or`, // traitor
626                                       `er`, // builder
627                                       `ist`, // typist
628                                       `an`, // technician
629                                       `man`, // dustman, barman
630                                       `woman`, // policewoman
631                                       `ian`, // optician
632                                       `person`, // chairperson
633                                       `sperson`, // spokesperson
634                                       `ess`, // waitress
635                                       `ive` // representative
636     ];
637 
638 /** English Linking Verbs in Nominative Form.
639  */
640 static immutable englishLinkingVerbs = [`is`, `seem`, `look`, `appear to be`, `could be`];
641 static immutable swedishLinkingVerbs = [`är`, `verkar`, `ser`, `kan vara`];
642 
643 /** English Word Suffixes. */
644 static immutable wordSuffixes = [ allNounSuffixes ~ verbSuffixes ~ adjectiveSuffixes ].uniq.array;
645 
646 /** Return string $(D word) in plural optionally in $(D count). */
647 string inPlural(string word, int count = 2,
648                 string pluralWord = null)
649 {
650     if (count == 1 || word.length == 0)
651     {
652         return word; // it isn't actually inPlural
653     }
654     if (pluralWord !is null)
655     {
656         return pluralWord;
657     }
658     switch (word[$ - 1])
659     {
660         case 's':
661         case 'a', 'e', 'i', 'o', 'u':
662             return word ~ `es`;
663         case 'f':
664             return word[0 .. $-1] ~ `ves`;
665         case 'y':
666             return word[0 .. $-1] ~ `ies`;
667         default:
668             return word ~ `s`;
669     }
670 }
671 
672 /** Return $(D s) lemmatized (normalized).
673  *
674  * See_Also: https://en.wikipedia.org/wiki/Lemmatisation
675  */
676 S lemmatized(S)(S s) nothrow
677 if (isSomeString!S)
678 {
679     if      (s.among!(`be`, `is`, `am`, `are`)) return `be`;
680     else if (s.among!(`do`, `does`))            return `do`;
681     else return s;
682 }
683 
684 /**
685    TODO Reuse knet translation query instead.
686  */
687 string negationIn(Lang lang) nothrow @nogc
688 {
689     switch (lang) with (Lang)
690     {
691     case en: return `not`;
692     case sv: return `inte`;
693     case de: return `nicht`;
694     default: return `not`;
695     }
696 }
697 
698 enum Manner
699 {
700     // TODO add unknown
701     formal,
702     informal,
703     slang,
704     rude,
705 }
706 
707 /** Grammatical Case.
708  *
709  * See_Also: https://en.wikipedia.org/wiki/Grammatical_case
710  */
711 enum Case
712 {
713     unknown,
714     nominative,
715     genitive,
716     dative,
717     accusative,
718     ablative
719 }
720 
721 /** English Subject Pronouns.
722  *
723  * See_Also: https://en.wikipedia.org/wiki/Subject_pronoun
724  */
725 static immutable englishSubjectPronouns = [`I`, // 1st-person singular
726                                            `you`, // 2nd-person singular
727                                            `he`, `she`, `it`, // 3rd-person singular
728                                            `we`,              // 1st-person plural
729                                            `they`,            // 2nd-person plural
730                                            `what`,            // interrogate singular (Object)
731                                            `who`];            // interrogate singular
732 
733 /** Swedish Subject Pronouns.
734  *
735  * See_Also: https://en.wikipedia.org/wiki/Subject_pronoun
736  */
737 static immutable swedishSubjectPronouns = [`jag`, // 1st-person singular
738                                            `du`,  // 2nd-person singular
739                                            `han`, `hon`, `den`, `det`, // 3rd-person singular
740                                            `vi`,                       // 1st-person plural
741                                            `de`,                       // 2nd-person plural
742                                            `vad`,                      // interrogate singular (Object)
743                                            `vem`,                      // interrogate singular
744                                            `vilka`];                   // interrogate plural
745 
746 /** English Object Pronouns.
747  *
748  * See_Also: https://en.wikipedia.org/wiki/Object_pronoun
749  */
750 static immutable englishObjectPronouns = [`me`, // 1st-person singular
751                                           `you`, // 2nd-person singular
752                                           `him,`, `her`, // 3rd-person singular
753                                           `us`,          // 1st-person plural
754                                           `them`,        // 2nd-person plural
755                                           `whom`];       // interrogate singular
756 
757 /** Swedish Object Pronouns.
758  *
759  * See_Also: https://en.wikipedia.org/wiki/Object_pronoun
760  */
761 static immutable swedishObjectPronouns = [`mig`, `dig`,
762                                           `honom,`, `henne`,
763                                           `oss`,
764                                           `dem`];
765 
766 enum Casing
767 {
768     unknown,
769     lower,
770     upper,
771     capitalized,
772     camel
773 }