// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Concurrent; namespace PowerAccent.Common; /// /// Single source of truth for all Quick Accent character data. /// /// is the canonical registry of every language: its identity, group, /// resource identifier, and character mappings. The Settings UI derives its language /// list from this collection. /// /// /// and control the order /// in which characters appear in the Quick Accent popup. These are intentionally /// separate from so that popup ordering is explicit and not an /// accidental consequence of declaration order. /// /// /// When adding a new language: add a enum value, a /// entry to , a position in /// , and a resx string. /// /// public static class CharacterMappings { /// /// The canonical registry of all languages. Each entry defines the language's /// identity, group, resource identifier, and character mappings. /// Declaration order here does not affect the popup or settings display order; /// see and for that. /// public static readonly IReadOnlyList All = [ new(Language.SPECIAL, "Special", LanguageGroup.Special, new Dictionary { [LetterKey.VK_0] = ["₀", "⁰", "°", "↉", "₎", "⁾"], [LetterKey.VK_1] = ["₁", "¹", "½", "⅓", "¼", "⅕", "⅙", "⅐", "⅛", "⅑", "⅒"], [LetterKey.VK_2] = ["₂", "²", "⅔", "⅖"], [LetterKey.VK_3] = ["₃", "³", "¾", "⅗", "⅜"], [LetterKey.VK_4] = ["₄", "⁴", "⅘"], [LetterKey.VK_5] = ["₅", "⁵", "⅚", "⅝"], [LetterKey.VK_6] = ["₆", "⁶"], [LetterKey.VK_7] = ["₇", "⁷", "⅞"], [LetterKey.VK_8] = ["₈", "⁸", "∞"], [LetterKey.VK_9] = ["₉", "⁹", "₍", "⁽"], [LetterKey.VK_A] = ["ȧ", "ǽ", "∀", "ᵃ", "ₐ"], [LetterKey.VK_B] = ["ḃ", "ᵇ"], [LetterKey.VK_C] = ["ċ", "°C", "©", "ℂ", "∁", "ᶜ"], [LetterKey.VK_D] = ["ḍ", "ḋ", "∂", "ᵈ"], [LetterKey.VK_E] = ["∈", "∃", "∄", "∉", "ĕ", "ᵉ", "ₑ"], [LetterKey.VK_F] = ["ḟ", "°F", "ᶠ"], [LetterKey.VK_G] = ["ģ", "ǧ", "ġ", "ĝ", "ǥ", "ᵍ"], [LetterKey.VK_H] = ["ḣ", "ĥ", "ħ", "ʰ", "ₕ"], [LetterKey.VK_I] = ["ⁱ", "ᵢ"], [LetterKey.VK_J] = ["ĵ", "ʲ", "ⱼ"], [LetterKey.VK_K] = ["ķ", "ǩ", "ᵏ", "ₖ"], [LetterKey.VK_L] = ["ļ", "₺", "ˡ", "ₗ"], // ₺ is in VK_T for other languages, but not VK_L, so we add it here. [LetterKey.VK_M] = ["ṁ", "ᵐ", "ₘ"], [LetterKey.VK_N] = ["ņ", "ṅ", "ⁿ", "ℕ", "№", "ₙ"], [LetterKey.VK_O] = ["ȯ", "∅", "⌀", "ᵒ", "ₒ"], [LetterKey.VK_P] = ["ṗ", "℗", "∏", "¶", "ᵖ", "ₚ", "‰", "‱"], [LetterKey.VK_Q] = ["ℚ", "𐞥"], [LetterKey.VK_R] = ["ṙ", "®", "ℝ", "ʳ", "ᵣ"], [LetterKey.VK_S] = ["ṡ", "§", "∑", "∫", "ˢ", "ₛ"], [LetterKey.VK_T] = ["ţ", "ṫ", "ŧ", "™", "ᵗ", "ₜ"], [LetterKey.VK_U] = ["ŭ", "ᵘ", "ᵤ"], [LetterKey.VK_V] = ["V̇", "ᵛ", "ᵥ"], [LetterKey.VK_W] = ["ẇ", "ʷ"], [LetterKey.VK_X] = ["ẋ", "×", "ˣ", "ₓ"], [LetterKey.VK_Y] = ["ẏ", "ꝡ", "ʸ"], [LetterKey.VK_Z] = ["ʒ", "ǯ", "ℤ", "ᶻ"], [LetterKey.VK_COMMA] = ["∙", "₋", "⁻", "–", "√", "‟", "⟪", "⟫", "‛", "⟨", "⟩", "″", "‴", "⁗"], [LetterKey.VK_PERIOD] = ["…", "⁝", "\u0300", "\u0301", "\u0302", "\u0303", "\u0304", "\u0308", "\u030B", "\u030C"], [LetterKey.VK_MINUS] = ["~", "‐", "‑", "‒", "–", "—", "―", "⁓", "−", "⸺", "⸻", "∓", "₋", "⁻"], [LetterKey.VK_SLASH_] = ["÷", "√", "‽", "⸘"], [LetterKey.VK_DIVIDE_] = ["÷", "√"], [LetterKey.VK_MULTIPLY_] = ["×", "⋅", "ˣ", "ₓ"], [LetterKey.VK_PLUS] = ["≤", "≥", "≠", "≈", "≙", "⊕", "⊗", "±", "≅", "≡", "₊", "⁺", "₌", "⁼"], [LetterKey.VK_BACKSLASH] = ["`", "~"], }), // Belarusian Latin new(Language.BE, "Belarusian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_C] = ["ć", "č"], [LetterKey.VK_L] = ["ł"], [LetterKey.VK_N] = ["ń"], [LetterKey.VK_S] = ["ś", "š"], [LetterKey.VK_U] = ["ŭ"], [LetterKey.VK_Z] = ["ź", "ž"], [LetterKey.VK_COMMA] = ["„", "“", "«", "»"], }), new(Language.BE_CYRL, "Belarusian_Cyrillic", LanguageGroup.Language, new Dictionary { [LetterKey.VK_E] = ["ё"], [LetterKey.VK_G] = ["ґ"], [LetterKey.VK_I] = ["і"], [LetterKey.VK_U] = ["ў"], [LetterKey.VK_COMMA] = ["’", "„", "“", "«", "»"], }), new(Language.BG, "Bulgarian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_E] = ["€"], [LetterKey.VK_I] = ["ѝ"], [LetterKey.VK_COMMA] = ["„", "“", "«", "»"], }), new(Language.CA, "Catalan", LanguageGroup.Language, new Dictionary { [LetterKey.VK_1] = ["¡"], [LetterKey.VK_A] = ["à", "á"], [LetterKey.VK_C] = ["ç"], [LetterKey.VK_E] = ["è", "é", "€"], [LetterKey.VK_I] = ["ì", "í", "ï"], [LetterKey.VK_N] = ["ñ"], [LetterKey.VK_O] = ["ò", "ó"], [LetterKey.VK_U] = ["ù", "ú", "ü"], [LetterKey.VK_L] = ["·"], [LetterKey.VK_COMMA] = ["¿", "?", "¡", "!", "«", "»", "“", "”", "‘", "’"], [LetterKey.VK_SLASH_] = ["¿"], }), new(Language.CRH, "Crimean", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["â"], [LetterKey.VK_C] = ["ç"], [LetterKey.VK_E] = ["€"], [LetterKey.VK_G] = ["ğ"], [LetterKey.VK_H] = ["₴"], [LetterKey.VK_I] = ["ı", "İ"], [LetterKey.VK_N] = ["ñ"], [LetterKey.VK_O] = ["ö"], [LetterKey.VK_S] = ["ş"], [LetterKey.VK_T] = ["₺"], [LetterKey.VK_U] = ["ü"], }), // Currency symbols. This is a "special" language group as it's not a spoken // language, but rather a set of symbols used across languages. new(Language.CUR, "Currency", LanguageGroup.Special, new Dictionary { [LetterKey.VK_B] = ["฿", "в"], // Bulgarian Lev (лв) [LetterKey.VK_C] = ["¢", "₡", "č"], // Czech Koruna (Kč) [LetterKey.VK_D] = ["₫"], [LetterKey.VK_E] = ["€"], [LetterKey.VK_F] = ["ƒ"], [LetterKey.VK_H] = ["₴"], [LetterKey.VK_K] = ["₭"], [LetterKey.VK_L] = ["ł"], // Polish Złoty (zł) [LetterKey.VK_N] = ["л"], // Bulgarian Lev (лв) [LetterKey.VK_M] = ["₼"], [LetterKey.VK_P] = ["£", "₽", "₱"], [LetterKey.VK_R] = ["₹", "៛", "﷼"], [LetterKey.VK_S] = ["$", "₪"], [LetterKey.VK_T] = ["₮", "₺", "₸"], [LetterKey.VK_W] = ["₩"], [LetterKey.VK_Y] = ["¥"], }), new(Language.CY, "Welsh", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["â", "ä", "à", "á"], [LetterKey.VK_E] = ["ê", "ë", "è", "é"], [LetterKey.VK_I] = ["î", "ï", "ì", "í"], [LetterKey.VK_O] = ["ô", "ö", "ò", "ó"], [LetterKey.VK_P] = ["£"], [LetterKey.VK_U] = ["û", "ü", "ù", "ú"], [LetterKey.VK_Y] = ["ŷ", "ÿ", "ỳ", "ý"], [LetterKey.VK_W] = ["ŵ", "ẅ", "ẁ", "ẃ"], [LetterKey.VK_COMMA] = ["‘", "’", "“", "”"], }), new(Language.CZ, "Czech", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["á"], [LetterKey.VK_C] = ["č"], [LetterKey.VK_D] = ["ď"], [LetterKey.VK_E] = ["ě", "é"], [LetterKey.VK_I] = ["í"], [LetterKey.VK_N] = ["ň"], [LetterKey.VK_O] = ["ó"], [LetterKey.VK_R] = ["ř"], [LetterKey.VK_S] = ["š"], [LetterKey.VK_T] = ["ť"], [LetterKey.VK_U] = ["ů", "ú"], [LetterKey.VK_Y] = ["ý"], [LetterKey.VK_Z] = ["ž"], [LetterKey.VK_COMMA] = ["„", "“", "‚", "‘", "»", "«", "›", "‹"], }), new(Language.DK, "Danish", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["å", "æ"], [LetterKey.VK_E] = ["€"], [LetterKey.VK_O] = ["ø"], [LetterKey.VK_COMMA] = ["»", "«", "“", "”", "›", "‹", "‘", "’"], }), // Gaelic (Irish). new(Language.GA, "Gaeilge", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["á"], [LetterKey.VK_E] = ["é", "€"], [LetterKey.VK_I] = ["í"], [LetterKey.VK_O] = ["ó"], [LetterKey.VK_U] = ["ú"], [LetterKey.VK_COMMA] = ["“", "”", "‘", "’"], }), // Gaelic (Scottish). new(Language.GD, "Gaidhlig", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["à"], [LetterKey.VK_E] = ["è"], [LetterKey.VK_I] = ["ì"], [LetterKey.VK_O] = ["ò"], [LetterKey.VK_P] = ["£"], [LetterKey.VK_U] = ["ù"], [LetterKey.VK_COMMA] = ["“", "”", "‘", "’"], }), new(Language.DE, "German", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["ä"], [LetterKey.VK_E] = ["€"], [LetterKey.VK_O] = ["ö"], [LetterKey.VK_S] = ["ß"], [LetterKey.VK_U] = ["ü"], [LetterKey.VK_COMMA] = ["„", "“", "‚", "‘", "»", "«", "›", "‹"], }), new(Language.EL, "Greek", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["α", "ά"], [LetterKey.VK_B] = ["β"], [LetterKey.VK_C] = ["χ"], [LetterKey.VK_D] = ["δ"], [LetterKey.VK_E] = ["ε", "έ", "η", "ή", "€"], [LetterKey.VK_F] = ["φ"], [LetterKey.VK_G] = ["γ"], [LetterKey.VK_I] = ["ι", "ί"], [LetterKey.VK_K] = ["κ"], [LetterKey.VK_L] = ["λ"], [LetterKey.VK_M] = ["μ"], [LetterKey.VK_N] = ["ν"], [LetterKey.VK_O] = ["ο", "ό", "ω", "ώ"], [LetterKey.VK_P] = ["π", "φ", "ψ"], [LetterKey.VK_R] = ["ρ"], [LetterKey.VK_S] = ["σ", "ς"], [LetterKey.VK_T] = ["τ", "θ", "ϑ"], [LetterKey.VK_U] = ["υ", "ύ"], [LetterKey.VK_X] = ["ξ"], [LetterKey.VK_Y] = ["υ"], [LetterKey.VK_Z] = ["ζ"], [LetterKey.VK_COMMA] = ["“", "”", "«", "»"], }), new(Language.EST, "Estonian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["ä"], [LetterKey.VK_E] = ["€"], [LetterKey.VK_O] = ["ö", "õ"], [LetterKey.VK_U] = ["ü"], [LetterKey.VK_Z] = ["ž"], [LetterKey.VK_S] = ["š"], [LetterKey.VK_COMMA] = ["„", "“", "«", "»"], }), new(Language.EPO, "Esperanto", LanguageGroup.Language, new Dictionary { [LetterKey.VK_C] = ["ĉ"], [LetterKey.VK_G] = ["ĝ"], [LetterKey.VK_H] = ["ĥ"], [LetterKey.VK_J] = ["ĵ"], [LetterKey.VK_S] = ["ŝ"], [LetterKey.VK_U] = ["ŭ"], }), new(Language.FI, "Finnish", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["ä", "å"], [LetterKey.VK_E] = ["€"], [LetterKey.VK_O] = ["ö"], [LetterKey.VK_COMMA] = ["”", "’", "»"], }), new(Language.FR, "French", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["à", "â", "á", "ä", "ã", "æ"], [LetterKey.VK_C] = ["ç"], [LetterKey.VK_E] = ["é", "è", "ê", "ë", "€"], [LetterKey.VK_I] = ["î", "ï", "í", "ì"], [LetterKey.VK_O] = ["ô", "ö", "ó", "ò", "õ", "œ"], [LetterKey.VK_U] = ["û", "ù", "ü", "ú"], [LetterKey.VK_Y] = ["ÿ", "ý"], [LetterKey.VK_COMMA] = ["«", "»", "‹", "›", "“", "”", "‘", "’"], }), new(Language.GRC, "Greek_Polytonic", LanguageGroup.Special, new Dictionary { [LetterKey.VK_A] = ["α", "ἀ", "ἁ", "ὰ", "ά", "ᾶ", "ᾱ", "ᾰ", "ἂ", "ἃ", "ἄ", "ἅ", "ἆ", "ἇ", "ᾳ", "ᾀ", "ᾁ", "ᾴ", "ᾲ", "ᾷ", "ᾄ", "ᾅ", "ᾂ", "ᾃ", "ᾆ", "ᾇ"], [LetterKey.VK_B] = ["β"], [LetterKey.VK_C] = ["χ", "ϲ"], [LetterKey.VK_D] = ["δ"], [LetterKey.VK_E] = ["ε", "ἐ", "ἑ", "ὲ", "έ", "ἒ", "ἓ", "ἔ", "ἕ"], [LetterKey.VK_F] = ["φ", "ϝ"], [LetterKey.VK_G] = ["γ"], [LetterKey.VK_H] = ["η", "ἠ", "ἡ", "ὴ", "ή", "ῆ", "ἢ", "ἣ", "ἤ", "ἥ", "ἦ", "ἧ", "ῃ", "ᾐ", "ᾑ", "ῄ", "ῂ", "ῇ", "ᾔ", "ᾕ", "ᾒ", "ᾓ", "ᾖ", "ᾗ"], [LetterKey.VK_I] = ["ι", "ἰ", "ἱ", "ὶ", "ί", "ῖ", "ῑ", "ῐ", "ἲ", "ἳ", "ἴ", "ἵ", "ἶ", "ἷ", "ϊ", "ΐ", "ῒ", "ῗ"], [LetterKey.VK_K] = ["κ"], [LetterKey.VK_L] = ["λ"], [LetterKey.VK_M] = ["μ"], [LetterKey.VK_N] = ["ν"], [LetterKey.VK_O] = ["ο", "ὀ", "ὁ", "ὸ", "ό", "ὂ", "ὃ", "ὄ", "ὅ"], [LetterKey.VK_P] = ["π", "φ", "ψ", "ρ"], [LetterKey.VK_Q] = ["ϙ", "ϟ"], [LetterKey.VK_R] = ["ρ", "ῤ", "ῥ"], [LetterKey.VK_S] = ["σ", "ς", "ϛ", "ϲ", "ϡ"], [LetterKey.VK_T] = ["τ", "θ", "ϑ"], [LetterKey.VK_U] = ["υ", "ὐ", "ὑ", "ὺ", "ύ", "ῦ", "ῡ", "ῠ", "ὒ", "ὓ", "ὔ", "ὕ", "ὖ", "ὗ", "ϋ", "ΰ", "ῢ", "ῧ"], [LetterKey.VK_V] = ["β", "ϝ"], [LetterKey.VK_W] = ["ω", "ὠ", "ὡ", "ὼ", "ώ", "ῶ", "ὢ", "ὣ", "ὤ", "ὥ", "ὦ", "ὧ", "ῳ", "ᾠ", "ᾡ", "ῴ", "ῲ", "ῷ", "ᾤ", "ᾥ", "ᾢ", "ᾣ", "ᾦ", "ᾧ"], [LetterKey.VK_X] = ["ξ", "χ"], [LetterKey.VK_Y] = ["υ", "ὐ", "ὑ", "ὺ", "ύ", "ῦ", "ῡ", "ῠ", "ὒ", "ὓ", "ὔ", "ὕ", "ὖ", "ὗ", "ϋ", "ΰ", "ῢ", "ῧ"], [LetterKey.VK_Z] = ["ζ"], [LetterKey.VK_COMMA] = ["“", "”", "‘", "’", ";", "`", "´"], [LetterKey.VK_PERIOD] = ["·"], }), new(Language.HR, "Croatian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_C] = ["ć", "č"], [LetterKey.VK_D] = ["đ"], [LetterKey.VK_E] = ["€"], [LetterKey.VK_S] = ["š"], [LetterKey.VK_Z] = ["ž"], [LetterKey.VK_COMMA] = ["„", "“", "»", "«"], }), new(Language.HE, "Hebrew", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["שׂ", "שׁ", "\u05b0"], [LetterKey.VK_B] = ["׆"], [LetterKey.VK_E] = ["\u05b8", "\u05b3", "\u05bb"], [LetterKey.VK_G] = ["ױ"], [LetterKey.VK_H] = ["ײ", "ײַ", "ׯ", "\u05b4"], [LetterKey.VK_M] = ["\u05b5"], [LetterKey.VK_N] = ["₪"], [LetterKey.VK_P] = ["\u05b7", "\u05b2"], [LetterKey.VK_S] = ["\u05bc"], [LetterKey.VK_T] = ["ﭏ"], [LetterKey.VK_U] = ["וֹ", "וּ", "װ", "\u05b9"], [LetterKey.VK_X] = ["\u05b6", "\u05b1"], [LetterKey.VK_Y] = ["ױ"], [LetterKey.VK_COMMA] = ["”", "’", "'", "״", "׳"], [LetterKey.VK_PERIOD] = ["\u05ab", "\u05bd", "\u05bf"], [LetterKey.VK_MINUS] = ["־"], }), new(Language.HU, "Hungarian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["á"], [LetterKey.VK_E] = ["é"], [LetterKey.VK_I] = ["í"], [LetterKey.VK_O] = ["ó", "ő", "ö"], [LetterKey.VK_U] = ["ú", "ű", "ü"], [LetterKey.VK_Y] = ["ÿ", "ý"], [LetterKey.VK_COMMA] = ["„", "”", "»", "«"], }), new(Language.IS, "Icelandic", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["á", "æ"], [LetterKey.VK_D] = ["ð"], [LetterKey.VK_E] = ["é"], [LetterKey.VK_I] = ["í"], [LetterKey.VK_O] = ["ó", "ö"], [LetterKey.VK_U] = ["ú"], [LetterKey.VK_Y] = ["ý"], [LetterKey.VK_T] = ["þ"], [LetterKey.VK_COMMA] = ["„", "“", "‚", "‘"], }), // International Phonetic Alphabet. This is a "special" language group as it's not // a spoken language, but rather a set of symbols used across languages. new(Language.IPA, "IPA", LanguageGroup.Special, new Dictionary { [LetterKey.VK_A] = ["ɑ", "æ", "ɒ", "ɐ"], [LetterKey.VK_B] = ["β", "ʙ", "ɓ", "ʘ"], [LetterKey.VK_C] = ["ç", "χ", "ǂ"], [LetterKey.VK_D] = ["ð", "ɗ", "ɖ", "ǀ"], [LetterKey.VK_E] = ["ə", "ɛ", "ɚ", "ɘ", "ɜ", "ɵ", "ɞ", "æ", "œ"], [LetterKey.VK_F] = ["ɸ"], [LetterKey.VK_G] = ["ɡ", "ɣ", "ɢ", "ɠ", "ʛ"], [LetterKey.VK_H] = ["ɦ", "ħ", "ɥ", "ʜ", "ɧ", "ʱ"], [LetterKey.VK_I] = ["ɪ", "ɨ"], [LetterKey.VK_J] = ["ɟ", "ʝ", "ʄ"], [LetterKey.VK_L] = ["ɫ", "ʎ", "ɬ", "ɮ", "ɭ", "ʟ", "ɺ", "ꞎ", "ǁ"], [LetterKey.VK_M] = ["ɱ"], [LetterKey.VK_N] = ["ŋ", "ɲ", "ɳ", "ɴ"], [LetterKey.VK_O] = ["ɔ", "ø", "œ", "ɤ", "ɶ", "ʘ"], [LetterKey.VK_R] = ["ɹ", "ɾ", "ʁ", "ʀ", "ɻ", "ɽ"], [LetterKey.VK_S] = ["ʃ", "ɕ", "ʂ"], [LetterKey.VK_T] = ["θ", "ʈ", "ǃ"], [LetterKey.VK_U] = ["ʊ", "ʉ"], [LetterKey.VK_V] = ["ʌ", "ʋ", "ⱱ"], [LetterKey.VK_W] = ["ʍ", "ɯ", "ɰ"], [LetterKey.VK_X] = ["χ"], [LetterKey.VK_Y] = ["ʎ", "ʏ"], [LetterKey.VK_Z] = ["ʒ", "ʐ", "ʑ"], [LetterKey.VK_COMMA] = ["ʔ", "ʕ", "ʡ", "ʢ"], [LetterKey.VK_PERIOD] = ["ˈ", "ˌ", "ː", "ʼ", "\u031D", "\u0325", "\u031A", "\u0361", "\u035C"], [LetterKey.VK_SLASH_] = ["ʔ"], }), new(Language.IT, "Italian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["à"], [LetterKey.VK_E] = ["è", "é", "ə", "€"], [LetterKey.VK_I] = ["ì", "í"], [LetterKey.VK_O] = ["ò", "ó"], [LetterKey.VK_U] = ["ù", "ú"], [LetterKey.VK_COMMA] = ["«", "»", "“", "”", "‘", "’"], }), new(Language.KU, "Kurdish", LanguageGroup.Language, new Dictionary { [LetterKey.VK_C] = ["ç"], [LetterKey.VK_E] = ["ê", "€"], [LetterKey.VK_I] = ["î"], [LetterKey.VK_O] = ["ö", "ô"], [LetterKey.VK_L] = ["ł"], [LetterKey.VK_N] = ["ň"], [LetterKey.VK_R] = ["ř"], [LetterKey.VK_S] = ["ş"], [LetterKey.VK_U] = ["û", "ü"], [LetterKey.VK_COMMA] = ["«", "»", "“", "”"], }), new(Language.LT, "Lithuanian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["ą"], [LetterKey.VK_C] = ["č"], [LetterKey.VK_E] = ["ę", "ė", "€"], [LetterKey.VK_I] = ["į"], [LetterKey.VK_S] = ["š"], [LetterKey.VK_U] = ["ų", "ū"], [LetterKey.VK_Z] = ["ž"], [LetterKey.VK_COMMA] = ["„", "“", "‚", "‘"], }), new(Language.MK, "Macedonian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_E] = ["ѐ"], [LetterKey.VK_I] = ["ѝ"], [LetterKey.VK_COMMA] = ["„", "“", "’", "‘"], }), new(Language.MT, "Maltese", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["à"], [LetterKey.VK_C] = ["ċ"], [LetterKey.VK_E] = ["è", "€"], [LetterKey.VK_G] = ["ġ"], [LetterKey.VK_H] = ["ħ"], [LetterKey.VK_I] = ["ì"], [LetterKey.VK_O] = ["ò"], [LetterKey.VK_U] = ["ù"], [LetterKey.VK_Z] = ["ż"], }), new(Language.MI, "Maori", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["ā"], [LetterKey.VK_E] = ["ē"], [LetterKey.VK_I] = ["ī"], [LetterKey.VK_O] = ["ō"], [LetterKey.VK_S] = ["$"], [LetterKey.VK_U] = ["ū"], [LetterKey.VK_COMMA] = ["“", "”", "‘", "’"], }), new(Language.NL, "Dutch", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["á", "à", "ä"], [LetterKey.VK_C] = ["ç"], [LetterKey.VK_E] = ["é", "è", "ë", "ê", "€"], [LetterKey.VK_I] = ["í", "ï", "î"], [LetterKey.VK_N] = ["ñ"], [LetterKey.VK_O] = ["ó", "ö", "ô"], [LetterKey.VK_U] = ["ú", "ü", "û"], [LetterKey.VK_COMMA] = ["“", "„", "”", "‘", ",", "’"], }), new(Language.NO, "Norwegian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["å", "æ"], [LetterKey.VK_E] = ["€", "é"], [LetterKey.VK_O] = ["ø"], [LetterKey.VK_S] = ["$"], [LetterKey.VK_COMMA] = ["«", "»", ",", "‘", "’", "„", "“"], }), new(Language.PI, "Pinyin", LanguageGroup.Language, new Dictionary { [LetterKey.VK_1] = ["\u0304", "ˉ"], [LetterKey.VK_2] = ["\u0301", "ˊ"], [LetterKey.VK_3] = ["\u030c", "ˇ"], [LetterKey.VK_4] = ["\u0300", "ˋ"], [LetterKey.VK_5] = ["·"], [LetterKey.VK_A] = ["ā", "á", "ǎ", "à", "ɑ", "ɑ\u0304", "ɑ\u0301", "ɑ\u030c", "ɑ\u0300"], [LetterKey.VK_C] = ["ĉ"], [LetterKey.VK_E] = ["ē", "é", "ě", "è", "ê", "ê\u0304", "ế", "ê\u030c", "ề"], [LetterKey.VK_I] = ["ī", "í", "ǐ", "ì"], [LetterKey.VK_M] = ["m\u0304", "ḿ", "m\u030c", "m\u0300"], [LetterKey.VK_N] = ["n\u0304", "ń", "ň", "ǹ", "ŋ", "ŋ\u0304", "ŋ\u0301", "ŋ\u030c", "ŋ\u0300"], [LetterKey.VK_O] = ["ō", "ó", "ǒ", "ò"], [LetterKey.VK_S] = ["ŝ"], [LetterKey.VK_U] = ["ū", "ú", "ǔ", "ù", "ü", "ǖ", "ǘ", "ǚ", "ǜ"], [LetterKey.VK_V] = ["ü", "ǖ", "ǘ", "ǚ", "ǜ"], [LetterKey.VK_Y] = ["¥"], [LetterKey.VK_Z] = ["ẑ"], [LetterKey.VK_COMMA] = ["“", "”", "‘", "’", "「", "」", "『", "』"], }), // Proto-Indo-European. This is a "special" language group as it's not a spoken // language, but rather a reconstructed ancestor of many languages. new(Language.PIE, "Proto_Indo_European", LanguageGroup.Special, new Dictionary { [LetterKey.VK_A] = ["ā"], [LetterKey.VK_E] = ["ē"], [LetterKey.VK_O] = ["ō"], [LetterKey.VK_K] = ["ḱ"], [LetterKey.VK_G] = ["ǵ"], [LetterKey.VK_R] = ["r̥"], [LetterKey.VK_L] = ["l̥"], [LetterKey.VK_M] = ["m̥"], [LetterKey.VK_N] = ["n̥"], }), new(Language.PL, "Polish", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["ą"], [LetterKey.VK_C] = ["ć"], [LetterKey.VK_E] = ["ę", "€"], [LetterKey.VK_L] = ["ł"], [LetterKey.VK_N] = ["ń"], [LetterKey.VK_O] = ["ó"], [LetterKey.VK_S] = ["ś"], [LetterKey.VK_Z] = ["ż", "ź"], [LetterKey.VK_COMMA] = ["„", "”", "‘", "’", "»", "«"], }), new(Language.PT, "Portuguese", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["á", "à", "â", "ã", "ª"], [LetterKey.VK_C] = ["ç"], [LetterKey.VK_E] = ["é", "ê", "€"], [LetterKey.VK_I] = ["í"], [LetterKey.VK_O] = ["ô", "ó", "õ", "º"], [LetterKey.VK_S] = ["$"], [LetterKey.VK_U] = ["ú"], [LetterKey.VK_COMMA] = ["“", "”", "‘", "’", "«", "»"], }), // This language set covers both Pitjantjatjara and Yankunytjatjara dialects new(Language.PJT, "Pitjantjatjara", LanguageGroup.Language, new Dictionary { [LetterKey.VK_L] = ["ḻ"], [LetterKey.VK_N] = ["ṉ"], [LetterKey.VK_R] = ["ṟ"], [LetterKey.VK_T] = ["ṯ"], }), new(Language.RO, "Romanian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["ă", "â"], [LetterKey.VK_I] = ["î"], [LetterKey.VK_S] = ["ș"], [LetterKey.VK_T] = ["ț"], [LetterKey.VK_COMMA] = ["„", "”", "«", "»"], }), // Middle Eastern Romanization. This is a "special" language group as it's not a // spoken language, but rather a set of characters used to romanize various Middle // Eastern languages. new(Language.ROM, "Romanization", LanguageGroup.Special, new Dictionary { [LetterKey.VK_A] = ["á", "â", "ă", "ā"], [LetterKey.VK_B] = ["ḇ"], [LetterKey.VK_C] = ["č", "ç"], [LetterKey.VK_D] = ["ḑ", "ḍ", "ḏ", "ḏ\u0323"], [LetterKey.VK_E] = ["ê", "ě", "ĕ", "ē", "é", "ə"], [LetterKey.VK_G] = ["ġ", "ǧ", "ğ", "ḡ", "g\u0303", "g\u0331"], [LetterKey.VK_H] = ["ḧ", "ḩ", "ḥ", "ḫ", "h\u0331"], [LetterKey.VK_I] = ["í", "ı", "î", "ī", "ı\u0307\u0304"], [LetterKey.VK_J] = ["ǰ", "j\u0331"], [LetterKey.VK_K] = ["ḳ", "ḵ"], [LetterKey.VK_L] = ["ł"], [LetterKey.VK_N] = ["ⁿ", "ñ"], [LetterKey.VK_O] = ["ó", "ô", "ö", "ŏ", "ō", "ȫ"], [LetterKey.VK_P] = ["p\u0304"], [LetterKey.VK_R] = ["ṙ", "ṛ"], [LetterKey.VK_S] = ["ś", "š", "ş", "ṣ", "s\u0331", "ṣ\u0304"], [LetterKey.VK_T] = ["ẗ", "ţ", "ṭ", "ṯ"], [LetterKey.VK_U] = ["ú", "û", "ü", "ū", "ǖ"], [LetterKey.VK_V] = ["v\u0307", "ṿ", "ᵛ"], [LetterKey.VK_Y] = ["̀y"], [LetterKey.VK_Z] = ["ż", "ž", "z\u0304", "z\u0327", "ẓ", "z\u0324", "ẕ"], [LetterKey.VK_PERIOD] = ["’", "ʾ", "ʿ", "′", "…"], }), new(Language.SK, "Slovak", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["á", "ä"], [LetterKey.VK_C] = ["č"], [LetterKey.VK_D] = ["ď"], [LetterKey.VK_E] = ["é", "€"], [LetterKey.VK_I] = ["í"], [LetterKey.VK_L] = ["ľ", "ĺ"], [LetterKey.VK_N] = ["ň"], [LetterKey.VK_O] = ["ó", "ô"], [LetterKey.VK_R] = ["ŕ"], [LetterKey.VK_S] = ["š"], [LetterKey.VK_T] = ["ť"], [LetterKey.VK_U] = ["ú"], [LetterKey.VK_Y] = ["ý"], [LetterKey.VK_Z] = ["ž"], [LetterKey.VK_COMMA] = ["„", "“", "‚", "‘", "»", "«", "›", "‹"], }), new(Language.SL, "Slovenian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_C] = ["č", "ć"], [LetterKey.VK_E] = ["€"], [LetterKey.VK_S] = ["š"], [LetterKey.VK_Z] = ["ž"], [LetterKey.VK_COMMA] = ["„", "“", "»", "«"], }), new(Language.SP, "Spanish", LanguageGroup.Language, new Dictionary { [LetterKey.VK_1] = ["¡"], [LetterKey.VK_A] = ["á"], [LetterKey.VK_E] = ["é", "€"], [LetterKey.VK_H] = ["ḥ"], [LetterKey.VK_I] = ["í"], [LetterKey.VK_L] = ["ḷ"], [LetterKey.VK_N] = ["ñ"], [LetterKey.VK_O] = ["ó"], [LetterKey.VK_U] = ["ú", "ü"], [LetterKey.VK_COMMA] = ["¿", "?", "¡", "!", "«", "»", "“", "”", "‘", "’"], [LetterKey.VK_SLASH_] = ["¿"], }), new(Language.SR, "Serbian", LanguageGroup.Language, new Dictionary { [LetterKey.VK_C] = ["ć", "č"], [LetterKey.VK_D] = ["đ"], [LetterKey.VK_S] = ["š"], [LetterKey.VK_Z] = ["ž"], [LetterKey.VK_COMMA] = ["„", "“", "‚", "’", "»", "«", "›", "‹"], }), new(Language.SR_CYRL, "Serbian_Cyrillic", LanguageGroup.Language, new Dictionary { [LetterKey.VK_D] = ["ђ", "џ"], [LetterKey.VK_L] = ["љ"], [LetterKey.VK_N] = ["њ"], [LetterKey.VK_C] = ["ћ"], }), new(Language.SV, "Swedish", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["å", "ä"], [LetterKey.VK_E] = ["é"], [LetterKey.VK_O] = ["ö"], [LetterKey.VK_COMMA] = ["”", "’", "»", "«"], }), new(Language.TK, "Turkish", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["â"], [LetterKey.VK_C] = ["ç"], [LetterKey.VK_E] = ["ë", "€"], [LetterKey.VK_G] = ["ğ"], [LetterKey.VK_I] = ["ı", "İ", "î",], [LetterKey.VK_O] = ["ö", "ô"], [LetterKey.VK_S] = ["ş"], [LetterKey.VK_T] = ["₺"], [LetterKey.VK_U] = ["ü", "û"], [LetterKey.VK_COMMA] = ["“", "”", "‘", "’", "«", "»", "‹", "›"], }), new(Language.VI, "Vietnamese", LanguageGroup.Language, new Dictionary { [LetterKey.VK_A] = ["à", "ả", "ã", "á", "ạ", "ă", "ằ", "ẳ", "ẵ", "ắ", "ặ", "â", "ầ", "ẩ", "ẫ", "ấ", "ậ"], [LetterKey.VK_D] = ["đ", "₫"], [LetterKey.VK_E] = ["è", "ẻ", "ẽ", "é", "ẹ", "ê", "ề", "ể", "ễ", "ế", "ệ"], [LetterKey.VK_I] = ["ì", "ỉ", "ĩ", "í", "ị"], [LetterKey.VK_O] = ["ò", "ỏ", "õ", "ó", "ọ", "ô", "ồ", "ổ", "ỗ", "ố", "ộ", "ơ", "ờ", "ở", "ỡ", "ớ", "ợ"], [LetterKey.VK_U] = ["ù", "ủ", "ũ", "ú", "ụ", "ư", "ừ", "ử", "ữ", "ứ", "ự"], [LetterKey.VK_Y] = ["ỳ", "ỷ", "ỹ", "ý", "ỵ"], }), ]; /// /// O(1) lookup from to its . /// Use this instead of searching when you have a language identity. /// public static readonly IReadOnlyDictionary LanguageLookup = All.ToDictionary(x => x.Id); /// /// The order in which language groups appear in the Quick Accent popup. /// Groups listed first have their characters shown first. /// This is intentionally separate from the enum order. /// public static readonly IReadOnlyList GroupDisplayOrder = [ LanguageGroup.UserDefined, LanguageGroup.Language, LanguageGroup.Special, ]; /// /// The order in which individual languages appear within their group in the Quick /// Accent popup. Position in this list is the display order; position in /// is irrelevant for popup ordering. /// Entries are sorted alphabetically by enum name. /// When adding a new language, insert it in alphabetical order. /// public static readonly IReadOnlyList DisplayOrder = [ // Spoken languages. Language.BE, Language.BE_CYRL, Language.BG, Language.CA, Language.CRH, Language.CY, Language.CZ, Language.DE, Language.DK, Language.EL, Language.EPO, Language.EST, Language.FI, Language.FR, Language.GA, Language.GD, Language.HE, Language.HR, Language.HU, Language.IS, Language.IT, Language.KU, Language.LT, Language.MI, Language.MK, Language.MT, Language.NL, Language.NO, Language.PI, Language.PJT, Language.PL, Language.PT, Language.RO, Language.SK, Language.SL, Language.SP, Language.SR, Language.SR_CYRL, Language.SV, Language.TK, Language.VI, // Symbols, non-spoken languages, and non-language-specific characters. Language.CUR, Language.GRC, Language.IPA, Language.PIE, Language.ROM, Language.SPECIAL, ]; // O(1) sort-key lookups derived from the display order lists above. private static readonly Dictionary _groupOrder = GroupDisplayOrder.Select((g, i) => (g, i)).ToDictionary(x => x.g, x => x.i); private static readonly Dictionary _languageOrder = DisplayOrder.Select((l, i) => (l, i)).ToDictionary(x => x.l, x => x.i); private static readonly ConcurrentDictionary _allLanguagesCache = new(); /// /// Returns the deduplicated set of characters for the given key across the specified /// languages, ordered by then . /// public static string[] GetCharacters(LetterKey letter, Language[] langs) { if (langs.Length == 0) { return []; } if (langs.Length == All.Count) { return _allLanguagesCache.GetOrAdd(letter, key => Collect(key, All)); } return Collect(letter, langs.Select(lang => LanguageLookup[lang])); } private static string[] Collect(LetterKey letter, IEnumerable maps) { var result = new List(); foreach (var map in maps .OrderBy(m => _groupOrder[m.Group]) .ThenBy(m => _languageOrder[m.Id])) { if (map.Characters.TryGetValue(letter, out var chars)) { result.AddRange(chars); } } return [.. result.Distinct()]; } }