diff --git a/Jint.Benchmark/IntlColdStartBenchmark.cs b/Jint.Benchmark/IntlColdStartBenchmark.cs new file mode 100644 index 0000000000..123e13cb3a --- /dev/null +++ b/Jint.Benchmark/IntlColdStartBenchmark.cs @@ -0,0 +1,43 @@ +using BenchmarkDotNet.Attributes; +using Jint.Native; + +namespace Jint.Benchmark; + +[MemoryDiagnoser] +public class IntlColdStartBenchmark +{ + [Benchmark] + public JsValue IntlNumberFormat() + { + var engine = new Engine(); + return engine.Evaluate("new Intl.NumberFormat('de', {notation: 'compact'}).format(1234567)"); + } + + [Benchmark] + public JsValue IntlDateTimeFormat() + { + var engine = new Engine(); + return engine.Evaluate("new Intl.DateTimeFormat('en').format(new Date())"); + } + + [Benchmark] + public JsValue IntlListFormat() + { + var engine = new Engine(); + return engine.Evaluate("new Intl.ListFormat('en').format(['a','b','c'])"); + } + + [Benchmark] + public JsValue IntlRelativeTimeFormat() + { + var engine = new Engine(); + return engine.Evaluate("new Intl.RelativeTimeFormat('en').format(-1, 'day')"); + } + + [Benchmark] + public JsValue LocaleCanonicalization() + { + var engine = new Engine(); + return engine.Evaluate("new Intl.Locale('en-US').maximize().toString()"); + } +} diff --git a/Jint/Jint.csproj b/Jint/Jint.csproj index d07b934ebc..68e7a621f4 100644 --- a/Jint/Jint.csproj +++ b/Jint/Jint.csproj @@ -42,13 +42,7 @@ - - - - - - diff --git a/Jint/Native/Intl/Data/CompactPatterns.Data.cs b/Jint/Native/Intl/Data/CompactPatterns.Data.cs new file mode 100644 index 0000000000..e53ab98855 --- /dev/null +++ b/Jint/Native/Intl/Data/CompactPatterns.Data.cs @@ -0,0 +1,166 @@ +namespace Jint.Native.Intl.Data; + +internal static partial class CompactPatterns +{ + private static readonly Dictionary _patterns = new(12, StringComparer.OrdinalIgnoreCase) + { + ["en"] = new LocaleCompactData + { + ShortThousand = "K", + ShortMillion = "M", + ShortBillion = "B", + ShortTrillion = "T", + Threshold = 1000, + ShortSpace = false, + }, + ["de"] = new LocaleCompactData + { + ShortThousand = "", + ShortMillion = "Mio.", + ShortBillion = "Mrd.", + ShortTrillion = "Bio.", + LongThousand = "Tausend", + LongMillion = "Millionen", + LongBillion = "Milliarden", + LongTrillion = "Billionen", + Threshold = 1000000, + ThresholdLong = 1000, + }, + ["ja"] = new LocaleCompactData + { + ShortThousand = "", + ShortMillion = "万", + ShortBillion = "億", + ShortTrillion = "兆", + LongThousand = "", + LongMillion = "万", + LongBillion = "億", + LongTrillion = "兆", + Threshold = 10000, + DivisorMillion = 10000, + DivisorBillion = 100000000, + ShortSpace = false, + LongSpace = false, + }, + ["ko"] = new LocaleCompactData + { + ShortThousand = "천", + ShortMillion = "만", + ShortBillion = "억", + ShortTrillion = "조", + LongThousand = "천", + LongMillion = "만", + LongBillion = "억", + LongTrillion = "조", + Threshold = 1000, + DivisorMillion = 10000, + DivisorBillion = 100000000, + ShortSpace = false, + LongSpace = false, + }, + ["zh"] = new LocaleCompactData + { + ShortThousand = "", + ShortMillion = "万", + ShortBillion = "亿", + ShortTrillion = "兆", + LongThousand = "", + LongMillion = "万", + LongBillion = "亿", + LongTrillion = "兆", + Threshold = 10000, + DivisorMillion = 10000, + DivisorBillion = 100000000, + ShortSpace = false, + LongSpace = false, + }, + ["zh-TW"] = new LocaleCompactData + { + ShortThousand = "", + ShortMillion = "萬", + ShortBillion = "億", + ShortTrillion = "兆", + LongThousand = "", + LongMillion = "萬", + LongBillion = "億", + LongTrillion = "兆", + Threshold = 10000, + DivisorMillion = 10000, + DivisorBillion = 100000000, + ShortSpace = false, + LongSpace = false, + }, + ["fr"] = new LocaleCompactData + { + ShortThousand = "k", + ShortMillion = "M", + ShortBillion = "Md", + ShortTrillion = "Bn", + LongThousand = "millier", + LongMillion = "millions", + LongBillion = "milliards", + LongTrillion = "billions", + Threshold = 1000, + }, + ["es"] = new LocaleCompactData + { + ShortThousand = "k", + ShortMillion = "M", + ShortBillion = "mil M", + ShortTrillion = "B", + LongThousand = "mil", + LongMillion = "millones", + LongBillion = "mil millones", + LongTrillion = "billones", + Threshold = 1000, + }, + ["it"] = new LocaleCompactData + { + ShortThousand = "", + ShortMillion = "Mln", + ShortBillion = "Mrd", + ShortTrillion = "Bln", + LongThousand = "mila", + LongMillion = "milioni", + LongBillion = "miliardi", + LongTrillion = "bilioni", + Threshold = 1000000, + }, + ["pt"] = new LocaleCompactData + { + ShortThousand = "mil", + ShortMillion = "mi", + ShortBillion = "bi", + ShortTrillion = "tri", + LongThousand = "mil", + LongMillion = "milhões", + LongBillion = "bilhões", + LongTrillion = "trilhões", + Threshold = 1000, + }, + ["ru"] = new LocaleCompactData + { + ShortThousand = "тыс.", + ShortMillion = "млн", + ShortBillion = "млрд", + ShortTrillion = "трлн", + LongThousand = "тысяч", + LongMillion = "миллионов", + LongBillion = "миллиардов", + LongTrillion = "триллионов", + Threshold = 1000, + }, + ["ar"] = new LocaleCompactData + { + ShortThousand = "ألف", + ShortMillion = "مليون", + ShortBillion = "مليار", + ShortTrillion = "ترليون", + LongThousand = "ألف", + LongMillion = "مليون", + LongBillion = "مليار", + LongTrillion = "ترليون", + Threshold = 1000, + }, + }; +} diff --git a/Jint/Native/Intl/Data/CompactPatterns.cs b/Jint/Native/Intl/Data/CompactPatterns.cs index a532491c7c..cf86a16eeb 100644 --- a/Jint/Native/Intl/Data/CompactPatterns.cs +++ b/Jint/Native/Intl/Data/CompactPatterns.cs @@ -1,29 +1,20 @@ -using System.Threading; - namespace Jint.Native.Intl.Data; /// /// Provides CLDR compact number patterns for locale-aware compact notation. -/// Data is loaded from embedded CompactPatterns.txt resource. /// -internal static class CompactPatterns +internal static partial class CompactPatterns { - private static readonly Lock _lock = new(); - private static Dictionary? _patterns; - private static volatile bool _loaded; - /// /// Gets compact patterns for a language code. /// Falls back to English if not found. /// public static LocaleCompactData GetPatterns(string? language) { - EnsureLoaded(); - if (!string.IsNullOrEmpty(language)) { // Try exact match first - if (_patterns!.TryGetValue(language!, out var data)) + if (_patterns.TryGetValue(language!, out var data)) { return data; } @@ -38,7 +29,7 @@ public static LocaleCompactData GetPatterns(string? language) language.Contains("-MO", StringComparison.OrdinalIgnoreCase) || language.Contains("-Hant", StringComparison.OrdinalIgnoreCase); var zhKey = isTraditional ? "zh-TW" : "zh"; - if (_patterns.TryGetValue(zhKey, out data)) + if (_patterns!.TryGetValue(zhKey, out data)) { return data; } @@ -57,142 +48,7 @@ public static LocaleCompactData GetPatterns(string? language) } // Fall back to English - return _patterns!.TryGetValue("en", out var enData) ? enData : LocaleCompactData.Default; - } - - private static void EnsureLoaded() - { - if (_loaded) - { - return; - } - - lock (_lock) - { - if (_loaded) - { - return; - } - - _patterns = new Dictionary(StringComparer.OrdinalIgnoreCase); - - var assembly = typeof(CompactPatterns).Assembly; - using var stream = assembly.GetManifestResourceStream("Jint.Native.Intl.Data.CompactPatterns.txt"); - if (stream is null) - { - _loaded = true; - return; - } - - using var reader = new StreamReader(stream); - string? currentLang = null; - LocaleCompactData? currentData = null; - - while (reader.ReadLine() is { } line) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - if (line.Length > 2 && line[0] == '[' && line[line.Length - 1] == ']') - { - // Save previous locale data - if (currentLang != null && currentData != null) - { - _patterns[currentLang] = currentData; - } - - currentLang = line.Substring(1, line.Length - 2); - currentData = new LocaleCompactData(); - continue; - } - - if (currentData == null) - { - continue; - } - - var eqIndex = line.IndexOf('='); - if (eqIndex < 0) - { - continue; - } - - var key = line.Substring(0, eqIndex); - var value = line.Substring(eqIndex + 1); - - switch (key) - { - case "short_thousand": - currentData.ShortThousand = value; - break; - case "short_million": - currentData.ShortMillion = value; - break; - case "short_billion": - currentData.ShortBillion = value; - break; - case "short_trillion": - currentData.ShortTrillion = value; - break; - case "long_thousand": - currentData.LongThousand = value; - break; - case "long_million": - currentData.LongMillion = value; - break; - case "long_billion": - currentData.LongBillion = value; - break; - case "long_trillion": - currentData.LongTrillion = value; - break; - case "threshold": - if (long.TryParse(value, System.Globalization.NumberStyles.Integer, - System.Globalization.CultureInfo.InvariantCulture, out var threshold)) - { - currentData.Threshold = threshold; - } - break; - case "threshold_long": - if (long.TryParse(value, System.Globalization.NumberStyles.Integer, - System.Globalization.CultureInfo.InvariantCulture, out var thresholdLong)) - { - currentData.ThresholdLong = thresholdLong; - } - break; - case "divisor_million": - if (long.TryParse(value, System.Globalization.NumberStyles.Integer, - System.Globalization.CultureInfo.InvariantCulture, out var divMillion)) - { - currentData.DivisorMillion = divMillion; - } - break; - case "divisor_billion": - if (long.TryParse(value, System.Globalization.NumberStyles.Integer, - System.Globalization.CultureInfo.InvariantCulture, out var divBillion)) - { - currentData.DivisorBillion = divBillion; - } - break; - case "short_space": - currentData.ShortSpace = !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase); - break; - case "long_space": - currentData.LongSpace = !string.Equals(value, "false", StringComparison.OrdinalIgnoreCase); - break; - } - } - - // Save last locale data - if (currentLang != null && currentData != null) - { - _patterns[currentLang] = currentData; - } - - _loaded = true; - } + return _patterns.TryGetValue("en", out var enData) ? enData : LocaleCompactData.Default; } internal sealed class LocaleCompactData diff --git a/Jint/Native/Intl/Data/LikelySubtagsData.cs b/Jint/Native/Intl/Data/LikelySubtagsData.cs index a774a6b978..9fd69e807b 100644 --- a/Jint/Native/Intl/Data/LikelySubtagsData.cs +++ b/Jint/Native/Intl/Data/LikelySubtagsData.cs @@ -6,13 +6,11 @@ namespace Jint.Native.Intl.Data; /// internal static class LikelySubtagsData { - private static Dictionary? _likelySubtags; - - private static Dictionary LikelySubtags => _likelySubtags ??= Load(); + private static readonly Lazy> _likelySubtags = new(Load); public static bool TryResolve(string key, out string value) { - return LikelySubtags.TryGetValue(key, out value!); + return _likelySubtags.Value.TryGetValue(key, out value!); } private static Dictionary Load() diff --git a/Jint/Native/Intl/Data/ListPatternsData.Data.cs b/Jint/Native/Intl/Data/ListPatternsData.Data.cs new file mode 100644 index 0000000000..d5b9d5947b --- /dev/null +++ b/Jint/Native/Intl/Data/ListPatternsData.Data.cs @@ -0,0 +1,56 @@ +namespace Jint.Native.Intl.Data; + +internal static partial class ListPatternsData +{ + private static readonly Dictionary> _patterns = new(4, StringComparer.OrdinalIgnoreCase) + { + ["en"] = new(9, StringComparer.Ordinal) + { + ["conjunction_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, and {1}", Two = "{0} and {1}" }, + ["conjunction_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, & {1}", Two = "{0} & {1}" }, + ["conjunction_narrow"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["disjunction_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, or {1}", Two = "{0} or {1}" }, + ["disjunction_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, or {1}", Two = "{0} or {1}" }, + ["disjunction_narrow"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, or {1}", Two = "{0} or {1}" }, + ["unit_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["unit_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["unit_narrow"] = new ListPatterns { Start = "{0} {1}", Middle = "{0} {1}", End = "{0} {1}", Two = "{0} {1}" }, + }, + ["es"] = new(9, StringComparer.Ordinal) + { + ["conjunction_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} y {1}", Two = "{0} y {1}" }, + ["conjunction_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} y {1}", Two = "{0} y {1}" }, + ["conjunction_narrow"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} y {1}", Two = "{0} y {1}" }, + ["disjunction_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} o {1}", Two = "{0} o {1}" }, + ["disjunction_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} o {1}", Two = "{0} o {1}" }, + ["disjunction_narrow"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} o {1}", Two = "{0} o {1}" }, + ["unit_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} y {1}", Two = "{0} y {1}" }, + ["unit_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0} y {1}" }, + ["unit_narrow"] = new ListPatterns { Start = "{0} {1}", Middle = "{0} {1}", End = "{0} {1}", Two = "{0} {1}" }, + }, + ["de"] = new(9, StringComparer.Ordinal) + { + ["conjunction_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} und {1}", Two = "{0} und {1}" }, + ["conjunction_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["conjunction_narrow"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["disjunction_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} oder {1}", Two = "{0} oder {1}" }, + ["disjunction_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} od. {1}", Two = "{0} od. {1}" }, + ["disjunction_narrow"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} od. {1}", Two = "{0} od. {1}" }, + ["unit_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["unit_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["unit_narrow"] = new ListPatterns { Start = "{0} {1}", Middle = "{0} {1}", End = "{0} {1}", Two = "{0} {1}" }, + }, + ["pl"] = new(9, StringComparer.Ordinal) + { + ["conjunction_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} i {1}", Two = "{0} i {1}" }, + ["conjunction_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} i {1}", Two = "{0} i {1}" }, + ["conjunction_narrow"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} i {1}", Two = "{0} i {1}" }, + ["disjunction_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} lub {1}", Two = "{0} lub {1}" }, + ["disjunction_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} lub {1}", Two = "{0} lub {1}" }, + ["disjunction_narrow"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0} lub {1}", Two = "{0} lub {1}" }, + ["unit_long"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["unit_short"] = new ListPatterns { Start = "{0}, {1}", Middle = "{0}, {1}", End = "{0}, {1}", Two = "{0}, {1}" }, + ["unit_narrow"] = new ListPatterns { Start = "{0} {1}", Middle = "{0} {1}", End = "{0} {1}", Two = "{0} {1}" }, + }, + }; +} diff --git a/Jint/Native/Intl/Data/ListPatternsData.cs b/Jint/Native/Intl/Data/ListPatternsData.cs index 8359923a34..107249372b 100644 --- a/Jint/Native/Intl/Data/ListPatternsData.cs +++ b/Jint/Native/Intl/Data/ListPatternsData.cs @@ -1,17 +1,10 @@ -using System.Threading; - namespace Jint.Native.Intl.Data; /// /// Provides CLDR list formatting patterns for locale-aware list formatting. -/// Data is loaded from embedded ListPatternsData.txt resource. /// -internal static class ListPatternsData +internal static partial class ListPatternsData { - private static readonly Lock _lock = new(); - private static Dictionary>? _patterns; - private static volatile bool _loaded; - /// /// Gets list patterns for a locale. /// Returns patterns grouped by type_style (e.g., "conjunction_long", "unit_narrow"). @@ -19,15 +12,13 @@ internal static class ListPatternsData /// public static Dictionary? GetPatternsForLocale(string locale) { - EnsureLoaded(); - if (!string.IsNullOrEmpty(locale)) { // Get language code from locale (e.g., "es" from "es-ES") var language = GetLanguageCode(locale); // Try to find patterns for this language - if (_patterns!.TryGetValue(language, out var data)) + if (_patterns.TryGetValue(language, out var data)) { return data; } @@ -36,7 +27,7 @@ internal static class ListPatternsData // Fall back to English if not found and not already English if (!IsEnglish(locale)) { - if (_patterns!.TryGetValue("en", out var enData)) + if (_patterns.TryGetValue("en", out var enData)) { return enData; } @@ -67,124 +58,4 @@ private static bool IsEnglish(string? locale) return locale!.StartsWith("en", StringComparison.OrdinalIgnoreCase); } - private static void EnsureLoaded() - { - if (_loaded) - { - return; - } - - lock (_lock) - { - if (_loaded) - { - return; - } - - _patterns = new Dictionary>(StringComparer.OrdinalIgnoreCase); - - var assembly = typeof(ListPatternsData).Assembly; - using var stream = assembly.GetManifestResourceStream("Jint.Native.Intl.Data.ListPatternsData.txt"); - if (stream is null) - { - _loaded = true; - return; - } - - using var reader = new StreamReader(stream); - string? currentLocale = null; - Dictionary? currentPatterns = null; - - // Temporary storage for building ListPatterns objects - var tempPatterns = new Dictionary>(StringComparer.Ordinal); - - while (reader.ReadLine() is { } line) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - if (line.Length > 2 && line[0] == '[' && line[line.Length - 1] == ']') - { - // Save previous locale data - if (currentLocale != null && tempPatterns.Count > 0) - { - currentPatterns = BuildListPatternsFromTemp(tempPatterns); - _patterns[currentLocale] = currentPatterns; - tempPatterns.Clear(); - } - - currentLocale = line.Substring(1, line.Length - 2); - continue; - } - - if (currentLocale == null) - { - continue; - } - - var eqIndex = line.IndexOf('='); - if (eqIndex < 0) - { - continue; - } - - var key = line.Substring(0, eqIndex); - var value = line.Substring(eqIndex + 1); - - // Parse key: type_style_position (e.g., "conjunction_long_end") - // Store in temp dictionary for later assembly - var parts = key.Split('_'); - if (parts.Length >= 3) - { - var type = parts[0]; // conjunction, disjunction, unit - var style = parts[1]; // long, short, narrow - var position = parts[2]; // start, middle, end, two - - var typeStyleKey = type + "_" + style; - if (!tempPatterns.TryGetValue(typeStyleKey, out var positionPatterns)) - { - positionPatterns = new Dictionary(StringComparer.Ordinal); - tempPatterns[typeStyleKey] = positionPatterns; - } - - positionPatterns[position] = value; - } - } - - // Save last locale data - if (currentLocale != null && tempPatterns.Count > 0) - { - currentPatterns = BuildListPatternsFromTemp(tempPatterns); - _patterns[currentLocale] = currentPatterns; - } - - _loaded = true; - } - } - - private static Dictionary BuildListPatternsFromTemp(Dictionary> tempPatterns) - { - var result = new Dictionary(StringComparer.Ordinal); - - foreach (var kvp in tempPatterns) - { - var typeStyleKey = kvp.Key; - var positionPatterns = kvp.Value; - - // Build ListPatterns object - var listPatterns = new ListPatterns - { - Start = positionPatterns.TryGetValue("start", out var start) ? start : "{0}, {1}", - Middle = positionPatterns.TryGetValue("middle", out var middle) ? middle : "{0}, {1}", - End = positionPatterns.TryGetValue("end", out var end) ? end : "{0}, {1}", - Two = positionPatterns.TryGetValue("two", out var two) ? two : "{0}, {1}" - }; - - result[typeStyleKey] = listPatterns; - } - - return result; - } } diff --git a/Jint/Native/Intl/Data/LocaleData.Data.cs b/Jint/Native/Intl/Data/LocaleData.Data.cs new file mode 100644 index 0000000000..1d420ba98e --- /dev/null +++ b/Jint/Native/Intl/Data/LocaleData.Data.cs @@ -0,0 +1,1056 @@ +namespace Jint.Native.Intl.Data; + +internal static partial class LocaleData +{ + private static readonly Dictionary _tagMappings = new(5, StringComparer.OrdinalIgnoreCase) + { + ["art-lojban"] = "jbo", + ["cel-gaulish"] = "xtg", + ["zh-guoyu"] = "zh", + ["zh-hakka"] = "hak", + ["zh-xiang"] = "hsn", + }; + + private static readonly Dictionary _languageMappings = new(354, StringComparer.OrdinalIgnoreCase) + { + ["aam"] = "aas", + ["aar"] = "aa", + ["abk"] = "ab", + ["adp"] = "dz", + ["afr"] = "af", + ["aju"] = "jrb", + ["aka"] = "ak", + ["alb"] = "sq", + ["als"] = "sq", + ["amh"] = "am", + ["ara"] = "ar", + ["arb"] = "ar", + ["arg"] = "an", + ["arm"] = "hy", + ["asd"] = "snz", + ["asm"] = "as", + ["aue"] = "ktz", + ["ava"] = "av", + ["ave"] = "ae", + ["aym"] = "ay", + ["ayr"] = "ay", + ["ayx"] = "nun", + ["aze"] = "az", + ["azj"] = "az", + ["bak"] = "ba", + ["bam"] = "bm", + ["baq"] = "eu", + ["bcc"] = "bal", + ["bcl"] = "bik", + ["bel"] = "be", + ["ben"] = "bn", + ["bgm"] = "bcg", + ["bh"] = "bho", + ["bih"] = "bho", + ["bis"] = "bi", + ["bjd"] = "drl", + ["bod"] = "bo", + ["bos"] = "bs", + ["bre"] = "br", + ["bul"] = "bg", + ["bur"] = "my", + ["bxk"] = "luy", + ["bxr"] = "bua", + ["cat"] = "ca", + ["ccq"] = "rki", + ["ces"] = "cs", + ["cha"] = "ch", + ["che"] = "ce", + ["chi"] = "zh", + ["chu"] = "cu", + ["chv"] = "cv", + ["cjr"] = "mom", + ["cka"] = "cmr", + ["cld"] = "syr", + ["cmk"] = "xch", + ["cmn"] = "zh", + ["cor"] = "kw", + ["cos"] = "co", + ["coy"] = "pij", + ["cqu"] = "quh", + ["cre"] = "cr", + ["cwd"] = "cr", + ["cym"] = "cy", + ["cze"] = "cs", + ["dan"] = "da", + ["deu"] = "de", + ["dgo"] = "doi", + ["dhd"] = "mwr", + ["dik"] = "din", + ["diq"] = "zza", + ["dit"] = "dif", + ["div"] = "dv", + ["drh"] = "mn", + ["dut"] = "nl", + ["dzo"] = "dz", + ["ekk"] = "et", + ["ell"] = "el", + ["emk"] = "man", + ["eng"] = "en", + ["epo"] = "eo", + ["esk"] = "ik", + ["est"] = "et", + ["eus"] = "eu", + ["ewe"] = "ee", + ["fao"] = "fo", + ["fas"] = "fa", + ["fat"] = "ak", + ["fij"] = "fj", + ["fin"] = "fi", + ["fra"] = "fr", + ["fre"] = "fr", + ["fry"] = "fy", + ["fuc"] = "ff", + ["ful"] = "ff", + ["gav"] = "dev", + ["gaz"] = "om", + ["gbo"] = "grb", + ["geo"] = "ka", + ["ger"] = "de", + ["gfx"] = "vaj", + ["ggn"] = "gvr", + ["gla"] = "gd", + ["gle"] = "ga", + ["glg"] = "gl", + ["glv"] = "gv", + ["gno"] = "gon", + ["gre"] = "el", + ["grn"] = "gn", + ["gti"] = "nyc", + ["gug"] = "gn", + ["guj"] = "gu", + ["guv"] = "duz", + ["gya"] = "gba", + ["hat"] = "ht", + ["hau"] = "ha", + ["hdn"] = "hai", + ["hea"] = "hmn", + ["heb"] = "he", + ["her"] = "hz", + ["him"] = "srx", + ["hin"] = "hi", + ["hmo"] = "ho", + ["hrr"] = "jal", + ["hrv"] = "hr", + ["hun"] = "hu", + ["hye"] = "hy", + ["ibi"] = "opa", + ["ibo"] = "ig", + ["ice"] = "is", + ["ido"] = "io", + ["iii"] = "ii", + ["ike"] = "iu", + ["iku"] = "iu", + ["ile"] = "ie", + ["ilw"] = "gal", + ["in"] = "id", + ["ina"] = "ia", + ["ind"] = "id", + ["ipk"] = "ik", + ["isl"] = "is", + ["ita"] = "it", + ["iw"] = "he", + ["jav"] = "jv", + ["jeg"] = "oyb", + ["ji"] = "yi", + ["jpn"] = "ja", + ["jw"] = "jv", + ["kal"] = "kl", + ["kan"] = "kn", + ["kas"] = "ks", + ["kat"] = "ka", + ["kau"] = "kr", + ["kaz"] = "kk", + ["kgc"] = "tdf", + ["kgh"] = "kml", + ["khk"] = "mn", + ["khm"] = "km", + ["kik"] = "ki", + ["kin"] = "rw", + ["kir"] = "ky", + ["kmr"] = "ku", + ["knc"] = "kr", + ["kng"] = "kg", + ["knn"] = "kok", + ["koj"] = "kwv", + ["kom"] = "kv", + ["kon"] = "kg", + ["kor"] = "ko", + ["kpv"] = "kv", + ["krm"] = "bmf", + ["ktr"] = "dtp", + ["kua"] = "kj", + ["kur"] = "ku", + ["kvs"] = "gdj", + ["kwq"] = "yam", + ["kxe"] = "tvd", + ["kzj"] = "dtp", + ["kzt"] = "dtp", + ["lao"] = "lo", + ["lat"] = "la", + ["lav"] = "lv", + ["lbk"] = "bnc", + ["lii"] = "raq", + ["lim"] = "li", + ["lin"] = "ln", + ["lit"] = "lt", + ["llo"] = "ngt", + ["lmm"] = "rmx", + ["ltz"] = "lb", + ["lub"] = "lu", + ["lug"] = "lg", + ["lvs"] = "lv", + ["mac"] = "mk", + ["mah"] = "mh", + ["mal"] = "ml", + ["mao"] = "mi", + ["mar"] = "mr", + ["may"] = "ms", + ["meg"] = "cir", + ["mhr"] = "chm", + ["mkd"] = "mk", + ["mlg"] = "mg", + ["mlt"] = "mt", + ["mnk"] = "man", + ["mo"] = "ro", + ["mol"] = "ro", + ["mon"] = "mn", + ["mri"] = "mi", + ["msa"] = "ms", + ["mst"] = "mry", + ["mup"] = "raj", + ["mwj"] = "vaj", + ["mya"] = "my", + ["myd"] = "aog", + ["myt"] = "mry", + ["nad"] = "xny", + ["nau"] = "na", + ["nav"] = "nv", + ["nbl"] = "nr", + ["ncp"] = "kdz", + ["nde"] = "nd", + ["ndo"] = "ng", + ["nep"] = "ne", + ["nld"] = "nl", + ["nno"] = "nn", + ["nns"] = "nbr", + ["nnx"] = "ngv", + ["no"] = "nb", + ["nob"] = "nb", + ["nor"] = "nb", + ["npi"] = "ne", + ["nts"] = "pij", + ["nya"] = "ny", + ["oci"] = "oc", + ["ojg"] = "oj", + ["oji"] = "oj", + ["ori"] = "or", + ["orm"] = "om", + ["ory"] = "or", + ["oss"] = "os", + ["oun"] = "vaj", + ["pan"] = "pa", + ["pbu"] = "ps", + ["pcr"] = "adx", + ["per"] = "fa", + ["pes"] = "fa", + ["pli"] = "pi", + ["plt"] = "mg", + ["pmc"] = "huw", + ["pmu"] = "phr", + ["pnb"] = "lah", + ["pol"] = "pl", + ["por"] = "pt", + ["ppa"] = "bfy", + ["ppr"] = "lcq", + ["pry"] = "prt", + ["pus"] = "ps", + ["puz"] = "pub", + ["que"] = "qu", + ["quz"] = "qu", + ["rmy"] = "rom", + ["roh"] = "rm", + ["ron"] = "ro", + ["rum"] = "ro", + ["run"] = "rn", + ["rus"] = "ru", + ["sag"] = "sg", + ["san"] = "sa", + ["sca"] = "hle", + ["scc"] = "sr", + ["scr"] = "hr", + ["sin"] = "si", + ["skk"] = "oyb", + ["slk"] = "sk", + ["slo"] = "sk", + ["slv"] = "sl", + ["sme"] = "se", + ["smo"] = "sm", + ["sna"] = "sn", + ["snd"] = "sd", + ["som"] = "so", + ["sot"] = "st", + ["spa"] = "es", + ["spy"] = "kln", + ["sqi"] = "sq", + ["src"] = "sc", + ["srd"] = "sc", + ["srp"] = "sr", + ["ssw"] = "ss", + ["sun"] = "su", + ["swa"] = "sw", + ["swe"] = "sv", + ["swh"] = "sw", + ["tah"] = "ty", + ["tam"] = "ta", + ["tat"] = "tt", + ["tdu"] = "dtp", + ["tel"] = "te", + ["tgk"] = "tg", + ["tgl"] = "fil", + ["tha"] = "th", + ["thc"] = "tpo", + ["thx"] = "oyb", + ["tib"] = "bo", + ["tie"] = "ras", + ["tir"] = "ti", + ["tkk"] = "twm", + ["tl"] = "fil", + ["tlw"] = "weo", + ["tmp"] = "tyj", + ["tne"] = "kak", + ["ton"] = "to", + ["tsf"] = "taj", + ["tsn"] = "tn", + ["tso"] = "ts", + ["ttq"] = "tmh", + ["tuk"] = "tk", + ["tur"] = "tr", + ["tw"] = "ak", + ["twi"] = "ak", + ["uig"] = "ug", + ["ukr"] = "uk", + ["umu"] = "del", + ["uok"] = "ema", + ["urd"] = "ur", + ["uzb"] = "uz", + ["uzn"] = "uz", + ["ven"] = "ve", + ["vie"] = "vi", + ["vol"] = "vo", + ["wel"] = "cy", + ["wln"] = "wa", + ["wol"] = "wo", + ["xba"] = "cax", + ["xho"] = "xh", + ["xia"] = "acn", + ["xkh"] = "waw", + ["xpe"] = "kpe", + ["xsj"] = "suj", + ["xsl"] = "den", + ["ybd"] = "rki", + ["ydd"] = "yi", + ["yid"] = "yi", + ["yma"] = "lrr", + ["ymt"] = "mtm", + ["yor"] = "yo", + ["yos"] = "zom", + ["yuu"] = "yug", + ["zai"] = "zap", + ["zha"] = "za", + ["zho"] = "zh", + ["zsm"] = "ms", + ["zul"] = "zu", + ["zyb"] = "za", + }; + + private static readonly Dictionary _complexLanguageMappings = new(7, StringComparer.OrdinalIgnoreCase) + { + ["cnr"] = new ComplexLanguageMapping("sr", null, "ME"), + ["drw"] = new ComplexLanguageMapping("fa", null, "AF"), + ["hbs"] = new ComplexLanguageMapping("sr", "Latn", null), + ["prs"] = new ComplexLanguageMapping("fa", null, "AF"), + ["sh"] = new ComplexLanguageMapping("sr", "Latn", null), + ["swc"] = new ComplexLanguageMapping("sw", null, "CD"), + ["tnf"] = new ComplexLanguageMapping("fa", null, "AF"), + }; + + private static readonly Dictionary _regionMappings = new(327, StringComparer.OrdinalIgnoreCase) + { + ["100"] = "BG", + ["104"] = "MM", + ["108"] = "BI", + ["112"] = "BY", + ["116"] = "KH", + ["120"] = "CM", + ["124"] = "CA", + ["132"] = "CV", + ["136"] = "KY", + ["140"] = "CF", + ["144"] = "LK", + ["148"] = "TD", + ["152"] = "CL", + ["156"] = "CN", + ["158"] = "TW", + ["162"] = "CX", + ["166"] = "CC", + ["170"] = "CO", + ["174"] = "KM", + ["175"] = "YT", + ["178"] = "CG", + ["180"] = "CD", + ["184"] = "CK", + ["188"] = "CR", + ["191"] = "HR", + ["192"] = "CU", + ["196"] = "CY", + ["203"] = "CZ", + ["204"] = "BJ", + ["208"] = "DK", + ["212"] = "DM", + ["214"] = "DO", + ["218"] = "EC", + ["222"] = "SV", + ["226"] = "GQ", + ["230"] = "ET", + ["231"] = "ET", + ["232"] = "ER", + ["233"] = "EE", + ["234"] = "FO", + ["238"] = "FK", + ["239"] = "GS", + ["242"] = "FJ", + ["246"] = "FI", + ["248"] = "AX", + ["249"] = "FR", + ["250"] = "FR", + ["254"] = "GF", + ["258"] = "PF", + ["260"] = "TF", + ["262"] = "DJ", + ["266"] = "GA", + ["268"] = "GE", + ["270"] = "GM", + ["275"] = "PS", + ["276"] = "DE", + ["278"] = "DE", + ["280"] = "DE", + ["288"] = "GH", + ["292"] = "GI", + ["296"] = "KI", + ["300"] = "GR", + ["304"] = "GL", + ["308"] = "GD", + ["312"] = "GP", + ["316"] = "GU", + ["320"] = "GT", + ["324"] = "GN", + ["328"] = "GY", + ["332"] = "HT", + ["334"] = "HM", + ["336"] = "VA", + ["340"] = "HN", + ["344"] = "HK", + ["348"] = "HU", + ["352"] = "IS", + ["356"] = "IN", + ["360"] = "ID", + ["364"] = "IR", + ["368"] = "IQ", + ["372"] = "IE", + ["376"] = "IL", + ["380"] = "IT", + ["384"] = "CI", + ["388"] = "JM", + ["392"] = "JP", + ["398"] = "KZ", + ["400"] = "JO", + ["404"] = "KE", + ["408"] = "KP", + ["410"] = "KR", + ["414"] = "KW", + ["417"] = "KG", + ["418"] = "LA", + ["422"] = "LB", + ["426"] = "LS", + ["428"] = "LV", + ["430"] = "LR", + ["434"] = "LY", + ["438"] = "LI", + ["440"] = "LT", + ["442"] = "LU", + ["446"] = "MO", + ["450"] = "MG", + ["454"] = "MW", + ["458"] = "MY", + ["462"] = "MV", + ["466"] = "ML", + ["470"] = "MT", + ["474"] = "MQ", + ["478"] = "MR", + ["480"] = "MU", + ["484"] = "MX", + ["492"] = "MC", + ["496"] = "MN", + ["498"] = "MD", + ["499"] = "ME", + ["500"] = "MS", + ["504"] = "MA", + ["508"] = "MZ", + ["512"] = "OM", + ["516"] = "NA", + ["520"] = "NR", + ["524"] = "NP", + ["528"] = "NL", + ["531"] = "CW", + ["533"] = "AW", + ["534"] = "SX", + ["535"] = "BQ", + ["540"] = "NC", + ["548"] = "VU", + ["554"] = "NZ", + ["558"] = "NI", + ["562"] = "NE", + ["566"] = "NG", + ["570"] = "NU", + ["574"] = "NF", + ["578"] = "NO", + ["580"] = "MP", + ["581"] = "UM", + ["583"] = "FM", + ["584"] = "MH", + ["585"] = "PW", + ["586"] = "PK", + ["591"] = "PA", + ["598"] = "PG", + ["600"] = "PY", + ["604"] = "PE", + ["608"] = "PH", + ["612"] = "PN", + ["616"] = "PL", + ["620"] = "PT", + ["624"] = "GW", + ["626"] = "TL", + ["630"] = "PR", + ["634"] = "QA", + ["638"] = "RE", + ["642"] = "RO", + ["643"] = "RU", + ["646"] = "RW", + ["652"] = "BL", + ["654"] = "SH", + ["659"] = "KN", + ["660"] = "AI", + ["662"] = "LC", + ["663"] = "MF", + ["666"] = "PM", + ["670"] = "VC", + ["674"] = "SM", + ["678"] = "ST", + ["682"] = "SA", + ["686"] = "SN", + ["688"] = "RS", + ["690"] = "SC", + ["694"] = "SL", + ["702"] = "SG", + ["703"] = "SK", + ["704"] = "VN", + ["705"] = "SI", + ["706"] = "SO", + ["710"] = "ZA", + ["716"] = "ZW", + ["720"] = "YE", + ["724"] = "ES", + ["728"] = "SS", + ["729"] = "SD", + ["732"] = "EH", + ["736"] = "SD", + ["740"] = "SR", + ["744"] = "SJ", + ["748"] = "SZ", + ["752"] = "SE", + ["756"] = "CH", + ["760"] = "SY", + ["762"] = "TJ", + ["764"] = "TH", + ["768"] = "TG", + ["772"] = "TK", + ["776"] = "TO", + ["780"] = "TT", + ["784"] = "AE", + ["788"] = "TN", + ["792"] = "TR", + ["795"] = "TM", + ["796"] = "TC", + ["798"] = "TV", + ["800"] = "UG", + ["804"] = "UA", + ["807"] = "MK", + ["818"] = "EG", + ["826"] = "GB", + ["830"] = "JE", + ["831"] = "GG", + ["832"] = "JE", + ["833"] = "IM", + ["834"] = "TZ", + ["840"] = "US", + ["850"] = "VI", + ["854"] = "BF", + ["858"] = "UY", + ["860"] = "UZ", + ["862"] = "VE", + ["876"] = "WF", + ["882"] = "WS", + ["886"] = "YE", + ["887"] = "YE", + ["891"] = "RS", + ["894"] = "ZM", + ["958"] = "AA", + ["959"] = "QM", + ["960"] = "QN", + ["962"] = "QP", + ["963"] = "QQ", + ["964"] = "QR", + ["965"] = "QS", + ["966"] = "QT", + ["967"] = "EU", + ["968"] = "QV", + ["969"] = "QW", + ["970"] = "QX", + ["971"] = "QY", + ["972"] = "QZ", + ["973"] = "XA", + ["974"] = "XB", + ["975"] = "XC", + ["976"] = "XD", + ["977"] = "XE", + ["978"] = "XF", + ["979"] = "XG", + ["980"] = "XH", + ["981"] = "XI", + ["982"] = "XJ", + ["983"] = "XK", + ["984"] = "XL", + ["985"] = "XM", + ["986"] = "XN", + ["987"] = "XO", + ["988"] = "XP", + ["989"] = "XQ", + ["990"] = "XR", + ["991"] = "XS", + ["992"] = "XT", + ["993"] = "XU", + ["994"] = "XV", + ["995"] = "XW", + ["996"] = "XX", + ["997"] = "XY", + ["998"] = "XZ", + ["999"] = "ZZ", + ["004"] = "AF", + ["008"] = "AL", + ["010"] = "AQ", + ["012"] = "DZ", + ["016"] = "AS", + ["020"] = "AD", + ["024"] = "AO", + ["028"] = "AG", + ["031"] = "AZ", + ["032"] = "AR", + ["036"] = "AU", + ["040"] = "AT", + ["044"] = "BS", + ["048"] = "BH", + ["050"] = "BD", + ["051"] = "AM", + ["052"] = "BB", + ["056"] = "BE", + ["060"] = "BM", + ["062"] = "034", + ["064"] = "BT", + ["068"] = "BO", + ["070"] = "BA", + ["072"] = "BW", + ["074"] = "BV", + ["076"] = "BR", + ["084"] = "BZ", + ["086"] = "IO", + ["090"] = "SB", + ["092"] = "VG", + ["096"] = "BN", + ["BU"] = "MM", + ["CS"] = "RS", + ["CT"] = "KI", + ["DD"] = "DE", + ["DY"] = "BJ", + ["FQ"] = "AQ", + ["FX"] = "FR", + ["HV"] = "BF", + ["JT"] = "UM", + ["MI"] = "UM", + ["NH"] = "VU", + ["NQ"] = "AQ", + ["PU"] = "UM", + ["PZ"] = "PA", + ["QU"] = "EU", + ["RH"] = "ZW", + ["TP"] = "TL", + ["UK"] = "GB", + ["VD"] = "VN", + ["WK"] = "UM", + ["YD"] = "YE", + ["YU"] = "RS", + ["ZR"] = "CD", + ["810"] = "RU", + ["NT"] = "SA", + ["SU"] = "RU", + ["AN"] = "CW", + }; + + private static readonly Dictionary _variantMappings = new(5, StringComparer.OrdinalIgnoreCase) + { + ["aaland"] = new VariantMapping("region", "AX"), + ["arevela"] = new VariantMapping("language", "hy"), + ["arevmda"] = new VariantMapping("language", "hyw"), + ["heploc"] = new VariantMapping("variant", "alalc97", "hepburn"), + ["polytoni"] = new VariantMapping("variant", "polyton"), + }; + + private static readonly Dictionary _languageVariantMappings = new(5, StringComparer.OrdinalIgnoreCase) + { + ["art+lojban"] = "jbo", + ["cel+gaulish"] = "xtg", + ["zh+guoyu"] = "zh", + ["zh+hakka"] = "hak", + ["zh+xiang"] = "hsn", + }; + + private static readonly Dictionary _scriptRegionMappings = new(12, StringComparer.OrdinalIgnoreCase) + { + ["Armn+SU"] = "AM", + ["Cyrl+SU"] = "RU", + ["Latn+SU"] = "RU", + ["Geor+SU"] = "GE", + ["Arab+SU"] = "UZ", + ["Armn+810"] = "AM", + ["Cyrl+810"] = "RU", + ["Latn+810"] = "RU", + ["Geor+810"] = "GE", + ["Arab+810"] = "UZ", + ["Cyrl+CS"] = "RS", + ["Latn+CS"] = "RS", + }; + + private static readonly Dictionary> _unicodeMappings = new(11, StringComparer.OrdinalIgnoreCase) + { + ["ca"] = new Dictionary(2, StringComparer.OrdinalIgnoreCase) + { + ["ethiopic-amete-alem"] = "ethioaa", + ["islamicc"] = "islamic-civil", + }, + ["kb"] = new Dictionary(1, StringComparer.OrdinalIgnoreCase) + { + ["yes"] = "true", + }, + ["kc"] = new Dictionary(1, StringComparer.OrdinalIgnoreCase) + { + ["yes"] = "true", + }, + ["kh"] = new Dictionary(1, StringComparer.OrdinalIgnoreCase) + { + ["yes"] = "true", + }, + ["kk"] = new Dictionary(1, StringComparer.OrdinalIgnoreCase) + { + ["yes"] = "true", + }, + ["kn"] = new Dictionary(1, StringComparer.OrdinalIgnoreCase) + { + ["yes"] = "true", + }, + ["ks"] = new Dictionary(2, StringComparer.OrdinalIgnoreCase) + { + ["primary"] = "level1", + ["tertiary"] = "level3", + }, + ["ms"] = new Dictionary(1, StringComparer.OrdinalIgnoreCase) + { + ["imperial"] = "uksystem", + }, + ["rg"] = new Dictionary(117, StringComparer.OrdinalIgnoreCase) + { + ["cn11"] = "cnbj", + ["cn12"] = "cntj", + ["cn13"] = "cnhe", + ["cn14"] = "cnsx", + ["cn15"] = "cnmn", + ["cn21"] = "cnln", + ["cn22"] = "cnjl", + ["cn23"] = "cnhl", + ["cn31"] = "cnsh", + ["cn32"] = "cnjs", + ["cn33"] = "cnzj", + ["cn34"] = "cnah", + ["cn35"] = "cnfj", + ["cn36"] = "cnjx", + ["cn37"] = "cnsd", + ["cn41"] = "cnha", + ["cn42"] = "cnhb", + ["cn43"] = "cnhn", + ["cn44"] = "cngd", + ["cn45"] = "cngx", + ["cn46"] = "cnhi", + ["cn50"] = "cncq", + ["cn51"] = "cnsc", + ["cn52"] = "cngz", + ["cn53"] = "cnyn", + ["cn54"] = "cnxz", + ["cn61"] = "cnsn", + ["cn62"] = "cngs", + ["cn63"] = "cnqh", + ["cn64"] = "cnnx", + ["cn65"] = "cnxj", + ["cz10a"] = "cz110", + ["cz10b"] = "cz111", + ["cz10c"] = "cz112", + ["cz10d"] = "cz113", + ["cz10e"] = "cz114", + ["cz10f"] = "cz115", + ["cz611"] = "cz663", + ["cz612"] = "cz632", + ["cz613"] = "cz633", + ["cz614"] = "cz634", + ["cz615"] = "cz635", + ["cz621"] = "cz641", + ["cz622"] = "cz642", + ["cz623"] = "cz643", + ["cz624"] = "cz644", + ["cz626"] = "cz646", + ["cz627"] = "cz647", + ["czjc"] = "cz31", + ["czjm"] = "cz64", + ["czka"] = "cz41", + ["czkr"] = "cz52", + ["czli"] = "cz51", + ["czmo"] = "cz80", + ["czol"] = "cz71", + ["czpa"] = "cz53", + ["czpl"] = "cz32", + ["czpr"] = "cz10", + ["czst"] = "cz20", + ["czus"] = "cz42", + ["czvy"] = "cz63", + ["czzl"] = "cz72", + ["fra"] = "frges", + ["frb"] = "frnaq", + ["frc"] = "frara", + ["frd"] = "frbfc", + ["fre"] = "frbre", + ["frf"] = "frcvl", + ["frg"] = "frges", + ["frh"] = "frcor", + ["fri"] = "frbfc", + ["frj"] = "fridf", + ["frk"] = "frocc", + ["frl"] = "frnaq", + ["frm"] = "frges", + ["frn"] = "frocc", + ["fro"] = "frhdf", + ["frp"] = "frnor", + ["frq"] = "frnor", + ["frr"] = "frpdl", + ["frs"] = "frhdf", + ["frt"] = "frnaq", + ["fru"] = "frpac", + ["frv"] = "frara", + ["laxn"] = "laxs", + ["lud"] = "lucl", + ["lug"] = "luec", + ["lul"] = "luca", + ["mrnkc"] = "mr13", + ["no23"] = "no50", + ["nzn"] = "nzauk", + ["nzs"] = "nzcan", + ["omba"] = "ombj", + ["omsh"] = "omsj", + ["plds"] = "pl02", + ["plkp"] = "pl04", + ["pllb"] = "pl08", + ["plld"] = "pl10", + ["pllu"] = "pl06", + ["plma"] = "pl12", + ["plmz"] = "pl14", + ["plop"] = "pl16", + ["plpd"] = "pl20", + ["plpk"] = "pl18", + ["plpm"] = "pl22", + ["plsk"] = "pl26", + ["plsl"] = "pl24", + ["plwn"] = "pl28", + ["plwp"] = "pl30", + ["plzp"] = "pl32", + ["tteto"] = "tttob", + ["ttrcm"] = "ttmrc", + ["ttwto"] = "tttob", + ["twkhq"] = "twkhh", + ["twtnq"] = "twtnn", + ["twtpq"] = "twnwt", + ["twtxq"] = "twtxg", + }, + ["sd"] = new Dictionary(117, StringComparer.OrdinalIgnoreCase) + { + ["cn11"] = "cnbj", + ["cn12"] = "cntj", + ["cn13"] = "cnhe", + ["cn14"] = "cnsx", + ["cn15"] = "cnmn", + ["cn21"] = "cnln", + ["cn22"] = "cnjl", + ["cn23"] = "cnhl", + ["cn31"] = "cnsh", + ["cn32"] = "cnjs", + ["cn33"] = "cnzj", + ["cn34"] = "cnah", + ["cn35"] = "cnfj", + ["cn36"] = "cnjx", + ["cn37"] = "cnsd", + ["cn41"] = "cnha", + ["cn42"] = "cnhb", + ["cn43"] = "cnhn", + ["cn44"] = "cngd", + ["cn45"] = "cngx", + ["cn46"] = "cnhi", + ["cn50"] = "cncq", + ["cn51"] = "cnsc", + ["cn52"] = "cngz", + ["cn53"] = "cnyn", + ["cn54"] = "cnxz", + ["cn61"] = "cnsn", + ["cn62"] = "cngs", + ["cn63"] = "cnqh", + ["cn64"] = "cnnx", + ["cn65"] = "cnxj", + ["cz10a"] = "cz110", + ["cz10b"] = "cz111", + ["cz10c"] = "cz112", + ["cz10d"] = "cz113", + ["cz10e"] = "cz114", + ["cz10f"] = "cz115", + ["cz611"] = "cz663", + ["cz612"] = "cz632", + ["cz613"] = "cz633", + ["cz614"] = "cz634", + ["cz615"] = "cz635", + ["cz621"] = "cz641", + ["cz622"] = "cz642", + ["cz623"] = "cz643", + ["cz624"] = "cz644", + ["cz626"] = "cz646", + ["cz627"] = "cz647", + ["czjc"] = "cz31", + ["czjm"] = "cz64", + ["czka"] = "cz41", + ["czkr"] = "cz52", + ["czli"] = "cz51", + ["czmo"] = "cz80", + ["czol"] = "cz71", + ["czpa"] = "cz53", + ["czpl"] = "cz32", + ["czpr"] = "cz10", + ["czst"] = "cz20", + ["czus"] = "cz42", + ["czvy"] = "cz63", + ["czzl"] = "cz72", + ["fra"] = "frges", + ["frb"] = "frnaq", + ["frc"] = "frara", + ["frd"] = "frbfc", + ["fre"] = "frbre", + ["frf"] = "frcvl", + ["frg"] = "frges", + ["frh"] = "frcor", + ["fri"] = "frbfc", + ["frj"] = "fridf", + ["frk"] = "frocc", + ["frl"] = "frnaq", + ["frm"] = "frges", + ["frn"] = "frocc", + ["fro"] = "frhdf", + ["frp"] = "frnor", + ["frq"] = "frnor", + ["frr"] = "frpdl", + ["frs"] = "frhdf", + ["frt"] = "frnaq", + ["fru"] = "frpac", + ["frv"] = "frara", + ["laxn"] = "laxs", + ["lud"] = "lucl", + ["lug"] = "luec", + ["lul"] = "luca", + ["mrnkc"] = "mr13", + ["no23"] = "no50", + ["nzn"] = "nzauk", + ["nzs"] = "nzcan", + ["omba"] = "ombj", + ["omsh"] = "omsj", + ["plds"] = "pl02", + ["plkp"] = "pl04", + ["pllb"] = "pl08", + ["plld"] = "pl10", + ["pllu"] = "pl06", + ["plma"] = "pl12", + ["plmz"] = "pl14", + ["plop"] = "pl16", + ["plpd"] = "pl20", + ["plpk"] = "pl18", + ["plpm"] = "pl22", + ["plsk"] = "pl26", + ["plsl"] = "pl24", + ["plwn"] = "pl28", + ["plwp"] = "pl30", + ["plzp"] = "pl32", + ["tteto"] = "tttob", + ["ttrcm"] = "ttmrc", + ["ttwto"] = "tttob", + ["twkhq"] = "twkhh", + ["twtnq"] = "twtnn", + ["twtpq"] = "twnwt", + ["twtxq"] = "twtxg", + }, + ["tz"] = new Dictionary(28, StringComparer.OrdinalIgnoreCase) + { + ["aqams"] = "nzakl", + ["cnckg"] = "cnsha", + ["cnhrb"] = "cnsha", + ["cnkhg"] = "cnurc", + ["cuba"] = "cuhav", + ["egypt"] = "egcai", + ["eire"] = "iedub", + ["est"] = "papty", + ["gmt0"] = "gmt", + ["hongkong"] = "hkhkg", + ["hst"] = "utcw10", + ["iceland"] = "isrey", + ["iran"] = "irthr", + ["israel"] = "jeruslm", + ["jamaica"] = "jmkin", + ["japan"] = "jptyo", + ["libya"] = "lytip", + ["mst"] = "utcw07", + ["navajo"] = "usden", + ["poland"] = "plwaw", + ["portugal"] = "ptlis", + ["prc"] = "cnsha", + ["roc"] = "twtpe", + ["rok"] = "krsel", + ["turkey"] = "trist", + ["uct"] = "utc", + ["usnavajo"] = "usden", + ["zulu"] = "utc", + }, + }; +} diff --git a/Jint/Native/Intl/Data/LocaleData.cs b/Jint/Native/Intl/Data/LocaleData.cs index dddff84d9a..ba686f56ab 100644 --- a/Jint/Native/Intl/Data/LocaleData.cs +++ b/Jint/Native/Intl/Data/LocaleData.cs @@ -1,308 +1,56 @@ -using System.Threading; - namespace Jint.Native.Intl.Data; /// /// Provides CLDR locale data for canonicalization. -/// Data is loaded from embedded LocaleData.txt resource. +/// Data is initialized inline in LocaleData.Data.cs. /// -internal static class LocaleData +internal static partial class LocaleData { - private static readonly Lock _lock = new(); - private static Dictionary? _tagMappings; - private static Dictionary? _languageMappings; - private static Dictionary? _complexLanguageMappings; - private static Dictionary? _regionMappings; - private static Dictionary? _variantMappings; - private static Dictionary? _languageVariantMappings; - private static Dictionary? _scriptRegionMappings; - private static Dictionary>? _unicodeMappings; - private static volatile bool _loaded; - /// /// Grandfathered tag mappings (e.g., "art-lojban" → "jbo"). /// - public static Dictionary TagMappings - { - get - { - EnsureLoaded(); - return _tagMappings!; - } - } + public static Dictionary TagMappings => _tagMappings; /// /// Simple language code mappings (e.g., "cmn" → "zh", "iw" → "he"). /// - public static Dictionary LanguageMappings - { - get - { - EnsureLoaded(); - return _languageMappings!; - } - } + public static Dictionary LanguageMappings => _languageMappings; /// /// Complex language mappings that may include script/region. /// - public static Dictionary ComplexLanguageMappings - { - get - { - EnsureLoaded(); - return _complexLanguageMappings!; - } - } + public static Dictionary ComplexLanguageMappings => _complexLanguageMappings; /// /// Region code mappings (e.g., "DD" → "DE", numeric to alpha). /// - public static Dictionary RegionMappings - { - get - { - EnsureLoaded(); - return _regionMappings!; - } - } + public static Dictionary RegionMappings => _regionMappings; /// /// Variant subtag mappings. /// - public static Dictionary VariantMappings - { - get - { - EnsureLoaded(); - return _variantMappings!; - } - } + public static Dictionary VariantMappings => _variantMappings; /// /// Language + variant mappings for grandfathered variants. /// Key format: "language+variant" (e.g., "art+lojban"), Value: new language (e.g., "jbo"). /// - public static Dictionary LanguageVariantMappings - { - get - { - EnsureLoaded(); - return _languageVariantMappings!; - } - } + public static Dictionary LanguageVariantMappings => _languageVariantMappings; /// /// Script + region mappings for deprecated regions (like SU). /// Key format: "Script+Region" (e.g., "Armn+SU"), Value: new region (e.g., "AM"). /// - public static Dictionary ScriptRegionMappings - { - get - { - EnsureLoaded(); - return _scriptRegionMappings!; - } - } + public static Dictionary ScriptRegionMappings => _scriptRegionMappings; /// /// Unicode extension value mappings, keyed by extension key (e.g., "ca", "tz"). /// - public static Dictionary> UnicodeMappings - { - get - { - EnsureLoaded(); - return _unicodeMappings!; - } - } - - private static void EnsureLoaded() - { - if (_loaded) - { - return; - } - - lock (_lock) - { - if (_loaded) - { - return; - } - - _tagMappings = new Dictionary(StringComparer.OrdinalIgnoreCase); - _languageMappings = new Dictionary(StringComparer.OrdinalIgnoreCase); - _complexLanguageMappings = new Dictionary(StringComparer.OrdinalIgnoreCase); - _regionMappings = new Dictionary(StringComparer.OrdinalIgnoreCase); - _variantMappings = new Dictionary(StringComparer.OrdinalIgnoreCase); - _languageVariantMappings = new Dictionary(StringComparer.OrdinalIgnoreCase); - _scriptRegionMappings = new Dictionary(StringComparer.OrdinalIgnoreCase); - _unicodeMappings = new Dictionary>(StringComparer.OrdinalIgnoreCase); - - var assembly = typeof(LocaleData).Assembly; - using var stream = assembly.GetManifestResourceStream("Jint.Native.Intl.Data.LocaleData.txt"); - if (stream is null) - { - _loaded = true; - return; - } - - using var reader = new StreamReader(stream); - string? currentSection = null; - - while (reader.ReadLine() is { } line) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - if (line.Length > 2 && line[0] == '[' && line[line.Length - 1] == ']') - { - currentSection = line.Substring(1, line.Length - 2); - continue; - } - - var eqIndex = line.IndexOf('='); - if (eqIndex < 0) - { - continue; - } - - var key = line.Substring(0, eqIndex); - var value = line.Substring(eqIndex + 1); - - switch (currentSection) - { - case "TAG_MAPPINGS": - _tagMappings[key] = value; - break; - - case "LANGUAGE_MAPPINGS": - _languageMappings[key] = value; - break; - - case "COMPLEX_LANGUAGE_MAPPINGS": - ParseComplexLanguageMapping(key, value); - break; - - case "REGION_MAPPINGS": - _regionMappings[key] = value; - break; - - case "VARIANT_MAPPINGS": - ParseVariantMapping(key, value); - break; - - case "LANGUAGE_VARIANT_MAPPINGS": - _languageVariantMappings![key] = value; - break; - - case "SCRIPT_REGION_MAPPINGS": - _scriptRegionMappings![key] = value; - break; - - case "UNICODE_MAPPINGS": - ParseUnicodeMapping(key, value); - break; - } - } - - _loaded = true; - } - } - - private static void ParseComplexLanguageMapping(string key, string value) - { - // Format: language,script:Latn,region:ME - var parts = value.Split(','); - string? script = null; - string? region = null; - - for (var i = 1; i < parts.Length; i++) - { - var part = parts[i]; - if (part.StartsWith("script:", StringComparison.Ordinal)) - { - script = part.Substring(7); - } - else if (part.StartsWith("region:", StringComparison.Ordinal)) - { - region = part.Substring(7); - } - } - - _complexLanguageMappings![key] = new ComplexLanguageMapping(parts[0], script, region); - } - - private static void ParseVariantMapping(string key, string value) - { - // Format: type,replacement[,prefix:variant] - var parts = value.Split(','); - if (parts.Length >= 2) - { - string? prefix = null; - for (var i = 2; i < parts.Length; i++) - { - if (parts[i].StartsWith("prefix:", StringComparison.Ordinal)) - { - prefix = parts[i].Substring(7); - } - } - - _variantMappings![key] = new VariantMapping(parts[0], parts[1], prefix); - } - } - - private static void ParseUnicodeMapping(string key, string value) - { - // Format key: keyType:oldValue (e.g., "ca:islamicc") - var colonIndex = key.IndexOf(':'); - if (colonIndex > 0) - { - var keyType = key.Substring(0, colonIndex); - var oldValue = key.Substring(colonIndex + 1); - - if (!_unicodeMappings!.TryGetValue(keyType, out var typeDict)) - { - typeDict = new Dictionary(StringComparer.OrdinalIgnoreCase); - _unicodeMappings[keyType] = typeDict; - } - - typeDict[oldValue] = value; - } - } - - internal readonly struct ComplexLanguageMapping - { - public ComplexLanguageMapping(string language, string? script, string? region) - { - Language = language; - Script = script; - Region = region; - } - - public string Language { get; } - public string? Script { get; } - public string? Region { get; } - } - - internal readonly struct VariantMapping - { - public VariantMapping(string type, string replacement, string? prefix = null) - { - Type = type; - Replacement = replacement; - Prefix = prefix; - } + public static Dictionary> UnicodeMappings => _unicodeMappings; - public string Type { get; } - public string Replacement { get; } + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Auto)] + internal readonly record struct ComplexLanguageMapping(string Language, string? Script, string? Region); - /// - /// Optional prefix variant that should be removed when this alias is applied. - /// - public string? Prefix { get; } - } + [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Auto)] + internal readonly record struct VariantMapping(string Type, string Replacement, string? Prefix = null); } diff --git a/Jint/Native/Intl/Data/RelativeTimePatternsData.Data.cs b/Jint/Native/Intl/Data/RelativeTimePatternsData.Data.cs new file mode 100644 index 0000000000..dd2350a884 --- /dev/null +++ b/Jint/Native/Intl/Data/RelativeTimePatternsData.Data.cs @@ -0,0 +1,1088 @@ +namespace Jint.Native.Intl.Data; + +internal static partial class RelativeTimePatternsData +{ + private static readonly Dictionary _data = new(4, StringComparer.OrdinalIgnoreCase) + { + ["en"] = new LocaleRelativeTimeData + { + Patterns = new(24, StringComparer.Ordinal) + { + ["second_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} second", + ["future_other"] = "in {0} seconds", + ["past_one"] = "{0} second ago", + ["past_other"] = "{0} seconds ago", + } + }, + ["second_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} sec.", + ["future_other"] = "in {0} sec.", + ["past_one"] = "{0} sec. ago", + ["past_other"] = "{0} sec. ago", + } + }, + ["second_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0}s", + ["future_other"] = "in {0}s", + ["past_one"] = "{0}s ago", + ["past_other"] = "{0}s ago", + } + }, + ["minute_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} minute", + ["future_other"] = "in {0} minutes", + ["past_one"] = "{0} minute ago", + ["past_other"] = "{0} minutes ago", + } + }, + ["minute_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} min.", + ["future_other"] = "in {0} min.", + ["past_one"] = "{0} min. ago", + ["past_other"] = "{0} min. ago", + } + }, + ["minute_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0}m", + ["future_other"] = "in {0}m", + ["past_one"] = "{0}m ago", + ["past_other"] = "{0}m ago", + } + }, + ["hour_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} hour", + ["future_other"] = "in {0} hours", + ["past_one"] = "{0} hour ago", + ["past_other"] = "{0} hours ago", + } + }, + ["hour_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} hr.", + ["future_other"] = "in {0} hr.", + ["past_one"] = "{0} hr. ago", + ["past_other"] = "{0} hr. ago", + } + }, + ["hour_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0}h", + ["future_other"] = "in {0}h", + ["past_one"] = "{0}h ago", + ["past_other"] = "{0}h ago", + } + }, + ["day_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} day", + ["future_other"] = "in {0} days", + ["past_one"] = "{0} day ago", + ["past_other"] = "{0} days ago", + } + }, + ["day_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} day", + ["future_other"] = "in {0} days", + ["past_one"] = "{0} day ago", + ["past_other"] = "{0} days ago", + } + }, + ["day_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0}d", + ["future_other"] = "in {0}d", + ["past_one"] = "{0}d ago", + ["past_other"] = "{0}d ago", + } + }, + ["week_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} week", + ["future_other"] = "in {0} weeks", + ["past_one"] = "{0} week ago", + ["past_other"] = "{0} weeks ago", + } + }, + ["week_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} wk.", + ["future_other"] = "in {0} wk.", + ["past_one"] = "{0} wk. ago", + ["past_other"] = "{0} wk. ago", + } + }, + ["week_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0}w", + ["future_other"] = "in {0}w", + ["past_one"] = "{0}w ago", + ["past_other"] = "{0}w ago", + } + }, + ["month_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} month", + ["future_other"] = "in {0} months", + ["past_one"] = "{0} month ago", + ["past_other"] = "{0} months ago", + } + }, + ["month_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} mo.", + ["future_other"] = "in {0} mo.", + ["past_one"] = "{0} mo. ago", + ["past_other"] = "{0} mo. ago", + } + }, + ["month_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0}mo", + ["future_other"] = "in {0}mo", + ["past_one"] = "{0}mo ago", + ["past_other"] = "{0}mo ago", + } + }, + ["quarter_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} quarter", + ["future_other"] = "in {0} quarters", + ["past_one"] = "{0} quarter ago", + ["past_other"] = "{0} quarters ago", + } + }, + ["quarter_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} qtr.", + ["future_other"] = "in {0} qtrs.", + ["past_one"] = "{0} qtr. ago", + ["past_other"] = "{0} qtrs. ago", + } + }, + ["quarter_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0}q", + ["future_other"] = "in {0}q", + ["past_one"] = "{0}q ago", + ["past_other"] = "{0}q ago", + } + }, + ["year_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} year", + ["future_other"] = "in {0} years", + ["past_one"] = "{0} year ago", + ["past_other"] = "{0} years ago", + } + }, + ["year_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} yr.", + ["future_other"] = "in {0} yr.", + ["past_one"] = "{0} yr. ago", + ["past_other"] = "{0} yr. ago", + } + }, + ["year_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0}y", + ["future_other"] = "in {0}y", + ["past_one"] = "{0}y ago", + ["past_other"] = "{0}y ago", + } + }, + } + }, + ["es"] = new LocaleRelativeTimeData + { + Patterns = new(24, StringComparer.Ordinal) + { + ["second_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} segundo", + ["future_other"] = "dentro de {0} segundos", + ["past_one"] = "hace {0} segundo", + ["past_other"] = "hace {0} segundos", + } + }, + ["second_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} s", + ["future_other"] = "dentro de {0} s", + ["past_one"] = "hace {0} s", + ["past_other"] = "hace {0} s", + } + }, + ["second_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "en {0} s", + ["future_other"] = "en {0} s", + ["past_one"] = "hace {0} s", + ["past_other"] = "hace {0} s", + } + }, + ["minute_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} minuto", + ["future_other"] = "dentro de {0} minutos", + ["past_one"] = "hace {0} minuto", + ["past_other"] = "hace {0} minutos", + } + }, + ["minute_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} min", + ["future_other"] = "dentro de {0} min", + ["past_one"] = "hace {0} min", + ["past_other"] = "hace {0} min", + } + }, + ["minute_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "en {0} min", + ["future_other"] = "en {0} min", + ["past_one"] = "hace {0} min", + ["past_other"] = "hace {0} min", + } + }, + ["hour_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} hora", + ["future_other"] = "dentro de {0} horas", + ["past_one"] = "hace {0} hora", + ["past_other"] = "hace {0} horas", + } + }, + ["hour_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} h", + ["future_other"] = "dentro de {0} h", + ["past_one"] = "hace {0} h", + ["past_other"] = "hace {0} h", + } + }, + ["hour_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "en {0} h", + ["future_other"] = "en {0} h", + ["past_one"] = "hace {0} h", + ["past_other"] = "hace {0} h", + } + }, + ["day_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} d\u00eda", + ["future_other"] = "dentro de {0} d\u00edas", + ["past_one"] = "hace {0} d\u00eda", + ["past_other"] = "hace {0} d\u00edas", + } + }, + ["day_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} d\u00eda", + ["future_other"] = "dentro de {0} d\u00edas", + ["past_one"] = "hace {0} d\u00eda", + ["past_other"] = "hace {0} d\u00edas", + } + }, + ["day_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "en {0} d", + ["future_other"] = "en {0} d", + ["past_one"] = "hace {0} d", + ["past_other"] = "hace {0} d", + } + }, + ["week_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} semana", + ["future_other"] = "dentro de {0} semanas", + ["past_one"] = "hace {0} semana", + ["past_other"] = "hace {0} semanas", + } + }, + ["week_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} sem.", + ["future_other"] = "dentro de {0} sem.", + ["past_one"] = "hace {0} sem.", + ["past_other"] = "hace {0} sem.", + } + }, + ["week_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "en {0} sem.", + ["future_other"] = "en {0} sem.", + ["past_one"] = "hace {0} sem.", + ["past_other"] = "hace {0} sem.", + } + }, + ["month_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} mes", + ["future_other"] = "dentro de {0} meses", + ["past_one"] = "hace {0} mes", + ["past_other"] = "hace {0} meses", + } + }, + ["month_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} m", + ["future_other"] = "dentro de {0} m", + ["past_one"] = "hace {0} m", + ["past_other"] = "hace {0} m", + } + }, + ["month_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "en {0} m", + ["future_other"] = "en {0} m", + ["past_one"] = "hace {0} m", + ["past_other"] = "hace {0} m", + } + }, + ["quarter_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} trimestre", + ["future_other"] = "dentro de {0} trimestres", + ["past_one"] = "hace {0} trimestre", + ["past_other"] = "hace {0} trimestres", + } + }, + ["quarter_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} trim.", + ["future_other"] = "dentro de {0} trim.", + ["past_one"] = "hace {0} trim.", + ["past_other"] = "hace {0} trim.", + } + }, + ["quarter_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "en {0} T", + ["future_other"] = "en {0} T", + ["past_one"] = "hace {0} T", + ["past_other"] = "hace {0} T", + } + }, + ["year_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} a\u00f1o", + ["future_other"] = "dentro de {0} a\u00f1os", + ["past_one"] = "hace {0} a\u00f1o", + ["past_other"] = "hace {0} a\u00f1os", + } + }, + ["year_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "dentro de {0} a", + ["future_other"] = "dentro de {0} a", + ["past_one"] = "hace {0} a", + ["past_other"] = "hace {0} a", + } + }, + ["year_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "en {0} a", + ["future_other"] = "en {0} a", + ["past_one"] = "hace {0} a", + ["past_other"] = "hace {0} a", + } + }, + } + }, + ["de"] = new LocaleRelativeTimeData + { + Patterns = new(24, StringComparer.Ordinal) + { + ["second_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Sekunde", + ["future_other"] = "in {0} Sekunden", + ["past_one"] = "vor {0} Sekunde", + ["past_other"] = "vor {0} Sekunden", + } + }, + ["second_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Sek.", + ["future_other"] = "in {0} Sek.", + ["past_one"] = "vor {0} Sek.", + ["past_other"] = "vor {0} Sek.", + } + }, + ["second_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} s", + ["future_other"] = "in {0} s", + ["past_one"] = "vor {0} s", + ["past_other"] = "vor {0} s", + } + }, + ["minute_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Minute", + ["future_other"] = "in {0} Minuten", + ["past_one"] = "vor {0} Minute", + ["past_other"] = "vor {0} Minuten", + } + }, + ["minute_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Min.", + ["future_other"] = "in {0} Min.", + ["past_one"] = "vor {0} Min.", + ["past_other"] = "vor {0} Min.", + } + }, + ["minute_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Min.", + ["future_other"] = "in {0} Min.", + ["past_one"] = "vor {0} Min.", + ["past_other"] = "vor {0} Min.", + } + }, + ["hour_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Stunde", + ["future_other"] = "in {0} Stunden", + ["past_one"] = "vor {0} Stunde", + ["past_other"] = "vor {0} Stunden", + } + }, + ["hour_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Std.", + ["future_other"] = "in {0} Std.", + ["past_one"] = "vor {0} Std.", + ["past_other"] = "vor {0} Std.", + } + }, + ["hour_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Std.", + ["future_other"] = "in {0} Std.", + ["past_one"] = "vor {0} Std.", + ["past_other"] = "vor {0} Std.", + } + }, + ["day_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Tag", + ["future_other"] = "in {0} Tagen", + ["past_one"] = "vor {0} Tag", + ["past_other"] = "vor {0} Tagen", + } + }, + ["day_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Tag", + ["future_other"] = "in {0} Tagen", + ["past_one"] = "vor {0} Tag", + ["past_other"] = "vor {0} Tagen", + } + }, + ["day_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} T", + ["future_other"] = "in {0} T", + ["past_one"] = "vor {0} T", + ["past_other"] = "vor {0} T", + } + }, + ["week_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Woche", + ["future_other"] = "in {0} Wochen", + ["past_one"] = "vor {0} Woche", + ["past_other"] = "vor {0} Wochen", + } + }, + ["week_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Wo.", + ["future_other"] = "in {0} Wo.", + ["past_one"] = "vor {0} Wo.", + ["past_other"] = "vor {0} Wo.", + } + }, + ["week_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} W", + ["future_other"] = "in {0} W", + ["past_one"] = "vor {0} W", + ["past_other"] = "vor {0} W", + } + }, + ["month_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Monat", + ["future_other"] = "in {0} Monaten", + ["past_one"] = "vor {0} Monat", + ["past_other"] = "vor {0} Monaten", + } + }, + ["month_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Mon.", + ["future_other"] = "in {0} Mon.", + ["past_one"] = "vor {0} Mon.", + ["past_other"] = "vor {0} Mon.", + } + }, + ["month_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} M", + ["future_other"] = "in {0} M", + ["past_one"] = "vor {0} M", + ["past_other"] = "vor {0} M", + } + }, + ["quarter_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Quartal", + ["future_other"] = "in {0} Quartalen", + ["past_one"] = "vor {0} Quartal", + ["past_other"] = "vor {0} Quartalen", + } + }, + ["quarter_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Quart.", + ["future_other"] = "in {0} Quart.", + ["past_one"] = "vor {0} Quart.", + ["past_other"] = "vor {0} Quart.", + } + }, + ["quarter_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Q", + ["future_other"] = "in {0} Q", + ["past_one"] = "vor {0} Q", + ["past_other"] = "vor {0} Q", + } + }, + ["year_long"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} Jahr", + ["future_other"] = "in {0} Jahren", + ["past_one"] = "vor {0} Jahr", + ["past_other"] = "vor {0} Jahren", + } + }, + ["year_short"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} J", + ["future_other"] = "in {0} J", + ["past_one"] = "vor {0} J", + ["past_other"] = "vor {0} J", + } + }, + ["year_narrow"] = new UnitStylePatterns + { + Patterns = new(4, StringComparer.Ordinal) + { + ["future_one"] = "in {0} J", + ["future_other"] = "in {0} J", + ["past_one"] = "vor {0} J", + ["past_other"] = "vor {0} J", + } + }, + } + }, + ["pl"] = new LocaleRelativeTimeData + { + Patterns = new(24, StringComparer.Ordinal) + { + ["second_long"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} sekund\u0119", + ["future_few"] = "za {0} sekundy", + ["future_many"] = "za {0} sekund", + ["future_other"] = "za {0} sekundy", + ["past_one"] = "{0} sekund\u0119 temu", + ["past_few"] = "{0} sekundy temu", + ["past_many"] = "{0} sekund temu", + ["past_other"] = "{0} sekundy temu", + } + }, + ["second_short"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} sek.", + ["future_few"] = "za {0} sek.", + ["future_many"] = "za {0} sek.", + ["future_other"] = "za {0} sek.", + ["past_one"] = "{0} sek. temu", + ["past_few"] = "{0} sek. temu", + ["past_many"] = "{0} sek. temu", + ["past_other"] = "{0} sek. temu", + } + }, + ["second_narrow"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} s", + ["future_few"] = "za {0} s", + ["future_many"] = "za {0} s", + ["future_other"] = "za {0} s", + ["past_one"] = "{0} s temu", + ["past_few"] = "{0} s temu", + ["past_many"] = "{0} s temu", + ["past_other"] = "{0} s temu", + } + }, + ["minute_long"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} minut\u0119", + ["future_few"] = "za {0} minuty", + ["future_many"] = "za {0} minut", + ["future_other"] = "za {0} minuty", + ["past_one"] = "{0} minut\u0119 temu", + ["past_few"] = "{0} minuty temu", + ["past_many"] = "{0} minut temu", + ["past_other"] = "{0} minuty temu", + } + }, + ["minute_short"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} min", + ["future_few"] = "za {0} min", + ["future_many"] = "za {0} min", + ["future_other"] = "za {0} min", + ["past_one"] = "{0} min temu", + ["past_few"] = "{0} min temu", + ["past_many"] = "{0} min temu", + ["past_other"] = "{0} min temu", + } + }, + ["minute_narrow"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} min", + ["future_few"] = "za {0} min", + ["future_many"] = "za {0} min", + ["future_other"] = "za {0} min", + ["past_one"] = "{0} min temu", + ["past_few"] = "{0} min temu", + ["past_many"] = "{0} min temu", + ["past_other"] = "{0} min temu", + } + }, + ["hour_long"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} godzin\u0119", + ["future_few"] = "za {0} godziny", + ["future_many"] = "za {0} godzin", + ["future_other"] = "za {0} godziny", + ["past_one"] = "{0} godzin\u0119 temu", + ["past_few"] = "{0} godziny temu", + ["past_many"] = "{0} godzin temu", + ["past_other"] = "{0} godziny temu", + } + }, + ["hour_short"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} godz.", + ["future_few"] = "za {0} godz.", + ["future_many"] = "za {0} godz.", + ["future_other"] = "za {0} godz.", + ["past_one"] = "{0} godz. temu", + ["past_few"] = "{0} godz. temu", + ["past_many"] = "{0} godz. temu", + ["past_other"] = "{0} godz. temu", + } + }, + ["hour_narrow"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} g.", + ["future_few"] = "za {0} g.", + ["future_many"] = "za {0} g.", + ["future_other"] = "za {0} g.", + ["past_one"] = "{0} g. temu", + ["past_few"] = "{0} g. temu", + ["past_many"] = "{0} g. temu", + ["past_other"] = "{0} g. temu", + } + }, + ["day_long"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} dzie\u0144", + ["future_few"] = "za {0} dni", + ["future_many"] = "za {0} dni", + ["future_other"] = "za {0} dnia", + ["past_one"] = "{0} dzie\u0144 temu", + ["past_few"] = "{0} dni temu", + ["past_many"] = "{0} dni temu", + ["past_other"] = "{0} dnia temu", + } + }, + ["day_short"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} dzie\u0144", + ["future_few"] = "za {0} dni", + ["future_many"] = "za {0} dni", + ["future_other"] = "za {0} dnia", + ["past_one"] = "{0} dzie\u0144 temu", + ["past_few"] = "{0} dni temu", + ["past_many"] = "{0} dni temu", + ["past_other"] = "{0} dnia temu", + } + }, + ["day_narrow"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} dzie\u0144", + ["future_few"] = "za {0} dni", + ["future_many"] = "za {0} dni", + ["future_other"] = "za {0} dnia", + ["past_one"] = "{0} dzie\u0144 temu", + ["past_few"] = "{0} dni temu", + ["past_many"] = "{0} dni temu", + ["past_other"] = "{0} dnia temu", + } + }, + ["week_long"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} tydzie\u0144", + ["future_few"] = "za {0} tygodnie", + ["future_many"] = "za {0} tygodni", + ["future_other"] = "za {0} tygodnia", + ["past_one"] = "{0} tydzie\u0144 temu", + ["past_few"] = "{0} tygodnie temu", + ["past_many"] = "{0} tygodni temu", + ["past_other"] = "{0} tygodnia temu", + } + }, + ["week_short"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} tydz.", + ["future_few"] = "za {0} tyg.", + ["future_many"] = "za {0} tyg.", + ["future_other"] = "za {0} tyg.", + ["past_one"] = "{0} tydz. temu", + ["past_few"] = "{0} tyg. temu", + ["past_many"] = "{0} tyg. temu", + ["past_other"] = "{0} tyg. temu", + } + }, + ["week_narrow"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} tydz.", + ["future_few"] = "za {0} tyg.", + ["future_many"] = "za {0} tyg.", + ["future_other"] = "za {0} tyg.", + ["past_one"] = "{0} tydz. temu", + ["past_few"] = "{0} tyg. temu", + ["past_many"] = "{0} tyg. temu", + ["past_other"] = "{0} tyg. temu", + } + }, + ["month_long"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} miesi\u0105c", + ["future_few"] = "za {0} miesi\u0105ce", + ["future_many"] = "za {0} miesi\u0119cy", + ["future_other"] = "za {0} miesi\u0105ca", + ["past_one"] = "{0} miesi\u0105c temu", + ["past_few"] = "{0} miesi\u0105ce temu", + ["past_many"] = "{0} miesi\u0119cy temu", + ["past_other"] = "{0} miesi\u0105ca temu", + } + }, + ["month_short"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} mies.", + ["future_few"] = "za {0} mies.", + ["future_many"] = "za {0} mies.", + ["future_other"] = "za {0} mies.", + ["past_one"] = "{0} mies. temu", + ["past_few"] = "{0} mies. temu", + ["past_many"] = "{0} mies. temu", + ["past_other"] = "{0} mies. temu", + } + }, + ["month_narrow"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} mies.", + ["future_few"] = "za {0} mies.", + ["future_many"] = "za {0} mies.", + ["future_other"] = "za {0} mies.", + ["past_one"] = "{0} mies. temu", + ["past_few"] = "{0} mies. temu", + ["past_many"] = "{0} mies. temu", + ["past_other"] = "{0} mies. temu", + } + }, + ["quarter_long"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} kwarta\u0142", + ["future_few"] = "za {0} kwarta\u0142y", + ["future_many"] = "za {0} kwarta\u0142\u00f3w", + ["future_other"] = "za {0} kwarta\u0142u", + ["past_one"] = "{0} kwarta\u0142 temu", + ["past_few"] = "{0} kwarta\u0142y temu", + ["past_many"] = "{0} kwarta\u0142\u00f3w temu", + ["past_other"] = "{0} kwarta\u0142u temu", + } + }, + ["quarter_short"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} kw.", + ["future_few"] = "za {0} kw.", + ["future_many"] = "za {0} kw.", + ["future_other"] = "za {0} kw.", + ["past_one"] = "{0} kw. temu", + ["past_few"] = "{0} kw. temu", + ["past_many"] = "{0} kw. temu", + ["past_other"] = "{0} kw. temu", + } + }, + ["quarter_narrow"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} kw.", + ["future_few"] = "za {0} kw.", + ["future_many"] = "za {0} kw.", + ["future_other"] = "za {0} kw.", + ["past_one"] = "{0} kw. temu", + ["past_few"] = "{0} kw. temu", + ["past_many"] = "{0} kw. temu", + ["past_other"] = "{0} kw. temu", + } + }, + ["year_long"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} rok", + ["future_few"] = "za {0} lata", + ["future_many"] = "za {0} lat", + ["future_other"] = "za {0} roku", + ["past_one"] = "{0} rok temu", + ["past_few"] = "{0} lata temu", + ["past_many"] = "{0} lat temu", + ["past_other"] = "{0} roku temu", + } + }, + ["year_short"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} rok", + ["future_few"] = "za {0} lata", + ["future_many"] = "za {0} lat", + ["future_other"] = "za {0} roku", + ["past_one"] = "{0} rok temu", + ["past_few"] = "{0} lata temu", + ["past_many"] = "{0} lat temu", + ["past_other"] = "{0} roku temu", + } + }, + ["year_narrow"] = new UnitStylePatterns + { + Patterns = new(8, StringComparer.Ordinal) + { + ["future_one"] = "za {0} rok", + ["future_few"] = "za {0} lata", + ["future_many"] = "za {0} lat", + ["future_other"] = "za {0} roku", + ["past_one"] = "{0} rok temu", + ["past_few"] = "{0} lata temu", + ["past_many"] = "{0} lat temu", + ["past_other"] = "{0} roku temu", + } + }, + } + }, + }; +} diff --git a/Jint/Native/Intl/Data/RelativeTimePatternsData.cs b/Jint/Native/Intl/Data/RelativeTimePatternsData.cs index fde97e5256..42cc8dbbbb 100644 --- a/Jint/Native/Intl/Data/RelativeTimePatternsData.cs +++ b/Jint/Native/Intl/Data/RelativeTimePatternsData.cs @@ -1,32 +1,23 @@ -using System.Threading; - namespace Jint.Native.Intl.Data; /// /// Provides CLDR relative time formatting patterns for locale-aware relative time formatting. -/// Data is loaded from embedded RelativeTimePatternsData.txt resource. /// -internal static class RelativeTimePatternsData +internal static partial class RelativeTimePatternsData { - private static readonly Lock _lock = new(); - private static Dictionary? _data; - private static volatile bool _loaded; - /// /// Gets relative time data for a locale. /// Falls back to English if locale not found. /// public static LocaleRelativeTimeData? GetDataForLocale(string locale) { - EnsureLoaded(); - if (!string.IsNullOrEmpty(locale)) { // Get language code from locale (e.g., "es" from "es-ES") var language = GetLanguageCode(locale); // Try to find data for this language - if (_data!.TryGetValue(language, out var data)) + if (_data.TryGetValue(language, out var data)) { return data; } @@ -35,7 +26,7 @@ internal static class RelativeTimePatternsData // Fall back to English if not found and not already English if (!IsEnglish(locale)) { - if (_data!.TryGetValue("en", out var enData)) + if (_data.TryGetValue("en", out var enData)) { return enData; } @@ -66,126 +57,6 @@ private static bool IsEnglish(string? locale) return locale!.StartsWith("en", StringComparison.OrdinalIgnoreCase); } - private static void EnsureLoaded() - { - if (_loaded) - { - return; - } - - lock (_lock) - { - if (_loaded) - { - return; - } - - _data = new Dictionary(StringComparer.OrdinalIgnoreCase); - - var assembly = typeof(RelativeTimePatternsData).Assembly; - using var stream = assembly.GetManifestResourceStream("Jint.Native.Intl.Data.RelativeTimePatternsData.txt"); - if (stream is null) - { - _loaded = true; - return; - } - - using var reader = new StreamReader(stream); - string? currentLocale = null; - - // Temporary storage for building patterns - var tempPatterns = new Dictionary>(StringComparer.Ordinal); - - while (reader.ReadLine() is { } line) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - if (line.Length > 2 && line[0] == '[' && line[line.Length - 1] == ']') - { - // Save previous locale data - if (currentLocale != null && tempPatterns.Count > 0) - { - var localeData = BuildLocaleDataFromTemp(tempPatterns); - _data[currentLocale] = localeData; - tempPatterns.Clear(); - } - - currentLocale = line.Substring(1, line.Length - 2); - continue; - } - - if (currentLocale == null) - { - continue; - } - - var eqIndex = line.IndexOf('='); - if (eqIndex < 0) - { - continue; - } - - var key = line.Substring(0, eqIndex); - var value = line.Substring(eqIndex + 1); - - // Parse key: unit_style_direction_pluralForm - // Example: "second_long_future_one" or "second_long_past_other" - var parts = key.Split('_'); - if (parts.Length >= 4) - { - var unit = parts[0]; // second, minute, hour, day, week, month, quarter, year - var style = parts[1]; // long, short, narrow - var direction = parts[2]; // future, past - var pluralForm = parts[3]; // one, few, many, other - - var unitStyleKey = unit + "_" + style; - if (!tempPatterns.TryGetValue(unitStyleKey, out var directionPatterns)) - { - directionPatterns = new Dictionary(StringComparer.Ordinal); - tempPatterns[unitStyleKey] = directionPatterns; - } - - var directionPluralKey = direction + "_" + pluralForm; - directionPatterns[directionPluralKey] = value; - } - } - - // Save last locale data - if (currentLocale != null && tempPatterns.Count > 0) - { - var localeData = BuildLocaleDataFromTemp(tempPatterns); - _data[currentLocale] = localeData; - } - - _loaded = true; - } - } - - private static LocaleRelativeTimeData BuildLocaleDataFromTemp(Dictionary> tempPatterns) - { - var patterns = new Dictionary(StringComparer.Ordinal); - - foreach (var kvp in tempPatterns) - { - var unitStyleKey = kvp.Key; - var directionPatterns = kvp.Value; - - var unitStylePatterns = new UnitStylePatterns - { - Patterns = new Dictionary(directionPatterns, StringComparer.Ordinal) - }; - - patterns[unitStyleKey] = unitStylePatterns; - } - - return new LocaleRelativeTimeData - { - Patterns = patterns - }; - } } /// diff --git a/Jint/Native/Intl/Data/UnitPatternsData.cs b/Jint/Native/Intl/Data/UnitPatternsData.cs index 2f7f9b9730..fe40e1bf09 100644 --- a/Jint/Native/Intl/Data/UnitPatternsData.cs +++ b/Jint/Native/Intl/Data/UnitPatternsData.cs @@ -1,16 +1,43 @@ -using System.Threading; - namespace Jint.Native.Intl.Data; /// /// Provides CLDR unit formatting patterns for locale-aware unit formatting. -/// Data is loaded from embedded UnitPatternsData.txt resource. /// internal static class UnitPatternsData { - private static readonly Lock _lock = new(); - private static Dictionary>? _patterns; - private static volatile bool _loaded; + private static readonly Dictionary> _patterns = new(5, StringComparer.OrdinalIgnoreCase) + { + ["en"] = new(3, StringComparer.Ordinal) + { + ["kilometer-per-hour_short"] = "{0} km/h", + ["kilometer-per-hour_narrow"] = "{0}km/h", + ["kilometer-per-hour_long"] = "{0} kilometers per hour", + }, + ["de"] = new(3, StringComparer.Ordinal) + { + ["kilometer-per-hour_short"] = "{0} km/h", + ["kilometer-per-hour_narrow"] = "{0} km/h", + ["kilometer-per-hour_long"] = "{0} Kilometer pro Stunde", + }, + ["ja"] = new(3, StringComparer.Ordinal) + { + ["kilometer-per-hour_short"] = "{0} km/h", + ["kilometer-per-hour_narrow"] = "{0}km/h", + ["kilometer-per-hour_long"] = "時速 {0} キロメートル", + }, + ["ko"] = new(3, StringComparer.Ordinal) + { + ["kilometer-per-hour_short"] = "{0}km/h", + ["kilometer-per-hour_narrow"] = "{0}km/h", + ["kilometer-per-hour_long"] = "시속 {0}킬로미터", + }, + ["zh"] = new(3, StringComparer.Ordinal) + { + ["kilometer-per-hour_short"] = "{0} 公里/小時", + ["kilometer-per-hour_narrow"] = "{0}公里/小時", + ["kilometer-per-hour_long"] = "每小時 {0} 公里", + }, + }; /// /// Gets unit patterns for a locale. @@ -19,15 +46,13 @@ internal static class UnitPatternsData /// public static Dictionary? GetPatternsForLocale(string locale) { - EnsureLoaded(); - if (!string.IsNullOrEmpty(locale)) { // Get language code from locale (e.g., "zh" from "zh-TW") var language = GetLanguageCode(locale); // Try to find patterns for this language - if (_patterns!.TryGetValue(language, out var data)) + if (_patterns.TryGetValue(language, out var data)) { return data; } @@ -36,7 +61,7 @@ internal static class UnitPatternsData // Fall back to English if not found and not already English if (!IsEnglish(locale)) { - if (_patterns!.TryGetValue("en", out var enData)) + if (_patterns.TryGetValue("en", out var enData)) { return enData; } @@ -66,79 +91,4 @@ private static bool IsEnglish(string? locale) return locale!.StartsWith("en", StringComparison.OrdinalIgnoreCase); } - - private static void EnsureLoaded() - { - if (_loaded) - { - return; - } - - lock (_lock) - { - if (_loaded) - { - return; - } - - _patterns = new Dictionary>(StringComparer.OrdinalIgnoreCase); - - var assembly = typeof(UnitPatternsData).Assembly; - using var stream = assembly.GetManifestResourceStream("Jint.Native.Intl.Data.UnitPatternsData.txt"); - if (stream is null) - { - _loaded = true; - return; - } - - using var reader = new StreamReader(stream); - string? currentLocale = null; - Dictionary? currentPatterns = null; - - while (reader.ReadLine() is { } line) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - if (line.Length > 2 && line[0] == '[' && line[line.Length - 1] == ']') - { - // Save previous locale data - if (currentLocale != null && currentPatterns != null) - { - _patterns[currentLocale] = currentPatterns; - } - - currentLocale = line.Substring(1, line.Length - 2); - currentPatterns = new Dictionary(StringComparer.Ordinal); - continue; - } - - if (currentLocale == null || currentPatterns == null) - { - continue; - } - - var eqIndex = line.IndexOf('='); - if (eqIndex < 0) - { - continue; - } - - var key = line.Substring(0, eqIndex); - var value = line.Substring(eqIndex + 1); - - currentPatterns[key] = value; - } - - // Save last locale data - if (currentLocale != null && currentPatterns != null) - { - _patterns[currentLocale] = currentPatterns; - } - - _loaded = true; - } - } } diff --git a/Jint/Native/Intl/Data/WeekData.Data.cs b/Jint/Native/Intl/Data/WeekData.Data.cs new file mode 100644 index 0000000000..35182c9f45 --- /dev/null +++ b/Jint/Native/Intl/Data/WeekData.Data.cs @@ -0,0 +1,256 @@ +namespace Jint.Native.Intl.Data; + +internal static partial class WeekData +{ + private static readonly Dictionary _firstDay = new(151, StringComparer.OrdinalIgnoreCase) + { + ["001"] = "mon", + ["AD"] = "mon", + ["AE"] = "mon", + ["AF"] = "sat", + ["AG"] = "sun", + ["AI"] = "mon", + ["AL"] = "mon", + ["AM"] = "mon", + ["AN"] = "mon", + ["AR"] = "mon", + ["AS"] = "sun", + ["AT"] = "mon", + ["AU"] = "mon", + ["AX"] = "mon", + ["AZ"] = "mon", + ["BA"] = "mon", + ["BD"] = "sun", + ["BE"] = "mon", + ["BG"] = "mon", + ["BH"] = "sat", + ["BM"] = "mon", + ["BN"] = "mon", + ["BR"] = "sun", + ["BS"] = "sun", + ["BT"] = "sun", + ["BW"] = "sun", + ["BY"] = "mon", + ["BZ"] = "sun", + ["CA"] = "sun", + ["CH"] = "mon", + ["CL"] = "mon", + ["CM"] = "mon", + ["CN"] = "mon", + ["CO"] = "sun", + ["CR"] = "mon", + ["CY"] = "mon", + ["CZ"] = "mon", + ["DE"] = "mon", + ["DJ"] = "sat", + ["DK"] = "mon", + ["DM"] = "sun", + ["DO"] = "sun", + ["DZ"] = "sat", + ["EC"] = "mon", + ["EE"] = "mon", + ["EG"] = "sat", + ["ES"] = "mon", + ["ET"] = "sun", + ["FI"] = "mon", + ["FJ"] = "mon", + ["FO"] = "mon", + ["FR"] = "mon", + ["GB"] = "mon", + ["GB-alt-variant"] = "sun", + ["GE"] = "mon", + ["GF"] = "mon", + ["GP"] = "mon", + ["GR"] = "mon", + ["GT"] = "sun", + ["GU"] = "sun", + ["HK"] = "sun", + ["HN"] = "sun", + ["HR"] = "mon", + ["HU"] = "mon", + ["ID"] = "sun", + ["IE"] = "mon", + ["IL"] = "sun", + ["IN"] = "sun", + ["IQ"] = "sat", + ["IR"] = "sat", + ["IS"] = "mon", + ["IT"] = "mon", + ["JM"] = "sun", + ["JO"] = "sat", + ["JP"] = "sun", + ["KE"] = "sun", + ["KG"] = "mon", + ["KH"] = "sun", + ["KR"] = "sun", + ["KW"] = "sat", + ["KZ"] = "mon", + ["LA"] = "sun", + ["LB"] = "mon", + ["LI"] = "mon", + ["LK"] = "mon", + ["LT"] = "mon", + ["LU"] = "mon", + ["LV"] = "mon", + ["LY"] = "sat", + ["MC"] = "mon", + ["MD"] = "mon", + ["ME"] = "mon", + ["MH"] = "sun", + ["MK"] = "mon", + ["MM"] = "sun", + ["MN"] = "mon", + ["MO"] = "sun", + ["MQ"] = "mon", + ["MT"] = "sun", + ["MV"] = "fri", + ["MX"] = "sun", + ["MY"] = "mon", + ["MZ"] = "sun", + ["NI"] = "sun", + ["NL"] = "mon", + ["NO"] = "mon", + ["NP"] = "sun", + ["NZ"] = "mon", + ["OM"] = "sat", + ["PA"] = "sun", + ["PE"] = "sun", + ["PH"] = "sun", + ["PK"] = "sun", + ["PL"] = "mon", + ["PR"] = "sun", + ["PT"] = "sun", + ["PY"] = "sun", + ["QA"] = "sat", + ["RE"] = "mon", + ["RO"] = "mon", + ["RS"] = "mon", + ["RU"] = "mon", + ["SA"] = "sun", + ["SD"] = "sat", + ["SE"] = "mon", + ["SG"] = "sun", + ["SI"] = "mon", + ["SK"] = "mon", + ["SM"] = "mon", + ["SV"] = "sun", + ["SY"] = "sat", + ["TH"] = "sun", + ["TJ"] = "mon", + ["TM"] = "mon", + ["TR"] = "mon", + ["TT"] = "sun", + ["TW"] = "sun", + ["UA"] = "mon", + ["UM"] = "sun", + ["US"] = "sun", + ["UY"] = "mon", + ["UZ"] = "mon", + ["VA"] = "mon", + ["VE"] = "sun", + ["VI"] = "sun", + ["VN"] = "mon", + ["WS"] = "sun", + ["XK"] = "mon", + ["YE"] = "sun", + ["ZA"] = "sun", + ["ZW"] = "sun", + }; + + private static readonly Dictionary _minDays = new(49, StringComparer.OrdinalIgnoreCase) + { + ["001"] = 1, + ["AD"] = 4, + ["AN"] = 4, + ["AT"] = 4, + ["AX"] = 4, + ["BE"] = 4, + ["BG"] = 4, + ["CH"] = 4, + ["CZ"] = 4, + ["DE"] = 4, + ["DK"] = 4, + ["EE"] = 4, + ["ES"] = 4, + ["FI"] = 4, + ["FJ"] = 4, + ["FO"] = 4, + ["FR"] = 4, + ["GB"] = 4, + ["GF"] = 4, + ["GG"] = 4, + ["GI"] = 4, + ["GP"] = 4, + ["GR"] = 4, + ["GU"] = 1, + ["HU"] = 4, + ["IE"] = 4, + ["IM"] = 4, + ["IS"] = 4, + ["IT"] = 4, + ["JE"] = 4, + ["LI"] = 4, + ["LT"] = 4, + ["LU"] = 4, + ["MC"] = 4, + ["MQ"] = 4, + ["NL"] = 4, + ["NO"] = 4, + ["PL"] = 4, + ["PT"] = 4, + ["RE"] = 4, + ["RU"] = 4, + ["SE"] = 4, + ["SJ"] = 4, + ["SK"] = 4, + ["SM"] = 4, + ["UM"] = 1, + ["US"] = 1, + ["VA"] = 4, + ["VI"] = 1, + }; + + private static readonly Dictionary _weekendStart = new(19, StringComparer.OrdinalIgnoreCase) + { + ["001"] = "sat", + ["AF"] = "thu", + ["BH"] = "fri", + ["DZ"] = "fri", + ["EG"] = "fri", + ["IL"] = "fri", + ["IN"] = "sun", + ["IQ"] = "fri", + ["IR"] = "fri", + ["JO"] = "fri", + ["KW"] = "fri", + ["LY"] = "fri", + ["OM"] = "fri", + ["QA"] = "fri", + ["SA"] = "fri", + ["SD"] = "fri", + ["SY"] = "fri", + ["UG"] = "sun", + ["YE"] = "fri", + }; + + private static readonly Dictionary _weekendEnd = new(17, StringComparer.OrdinalIgnoreCase) + { + ["001"] = "sun", + ["AF"] = "fri", + ["BH"] = "sat", + ["DZ"] = "sat", + ["EG"] = "sat", + ["IL"] = "sat", + ["IQ"] = "sat", + ["IR"] = "fri", + ["JO"] = "sat", + ["KW"] = "sat", + ["LY"] = "sat", + ["OM"] = "sat", + ["QA"] = "sat", + ["SA"] = "sat", + ["SD"] = "sat", + ["SY"] = "sat", + ["YE"] = "sat", + }; +} diff --git a/Jint/Native/Intl/Data/WeekData.cs b/Jint/Native/Intl/Data/WeekData.cs index af09dcda14..67388ece9c 100644 --- a/Jint/Native/Intl/Data/WeekData.cs +++ b/Jint/Native/Intl/Data/WeekData.cs @@ -1,71 +1,33 @@ -using System.Threading; - namespace Jint.Native.Intl.Data; /// /// Provides CLDR week data for locale-aware week information. -/// Data is loaded from embedded WeekData.txt resource. /// -internal static class WeekData +internal static partial class WeekData { - private static readonly Lock _lock = new(); - private static Dictionary? _firstDay; - private static Dictionary? _minDays; - private static Dictionary? _weekendStart; - private static Dictionary? _weekendEnd; - private static volatile bool _loaded; - /// /// First day of week per region (mon, tue, wed, thu, fri, sat, sun). /// Key "001" is the default/world value. /// - public static Dictionary FirstDay - { - get - { - EnsureLoaded(); - return _firstDay!; - } - } + public static Dictionary FirstDay => _firstDay; /// /// Minimum days in first week per region (typically 1 or 4). /// Key "001" is the default/world value. /// - public static Dictionary MinDays - { - get - { - EnsureLoaded(); - return _minDays!; - } - } + public static Dictionary MinDays => _minDays; /// /// Weekend start day per region. /// Key "001" is the default/world value (typically "sat"). /// - public static Dictionary WeekendStart - { - get - { - EnsureLoaded(); - return _weekendStart!; - } - } + public static Dictionary WeekendStart => _weekendStart; /// /// Weekend end day per region. /// Key "001" is the default/world value (typically "sun"). /// - public static Dictionary WeekendEnd - { - get - { - EnsureLoaded(); - return _weekendEnd!; - } - } + public static Dictionary WeekendEnd => _weekendEnd; /// /// Gets the first day of week for a region (1=Monday, 7=Sunday). @@ -81,15 +43,13 @@ public static int GetFirstDayOfWeek(string? region) /// public static string GetFirstDayName(string? region) { - EnsureLoaded(); - - if (!string.IsNullOrEmpty(region) && _firstDay!.TryGetValue(region!, out var day)) + if (!string.IsNullOrEmpty(region) && _firstDay.TryGetValue(region!, out var day)) { return day; } // Default to world value - return _firstDay!.TryGetValue("001", out var defaultDay) ? defaultDay : "mon"; + return _firstDay.TryGetValue("001", out var defaultDay) ? defaultDay : "mon"; } /// @@ -97,15 +57,13 @@ public static string GetFirstDayName(string? region) /// public static int GetMinDays(string? region) { - EnsureLoaded(); - - if (!string.IsNullOrEmpty(region) && _minDays!.TryGetValue(region!, out var days)) + if (!string.IsNullOrEmpty(region) && _minDays.TryGetValue(region!, out var days)) { return days; } // Default to world value - return _minDays!.TryGetValue("001", out var defaultDays) ? defaultDays : 1; + return _minDays.TryGetValue("001", out var defaultDays) ? defaultDays : 1; } /// @@ -113,26 +71,24 @@ public static int GetMinDays(string? region) /// public static int[] GetWeekend(string? region) { - EnsureLoaded(); - string startDay, endDay; - if (!string.IsNullOrEmpty(region) && _weekendStart!.TryGetValue(region!, out var start)) + if (!string.IsNullOrEmpty(region) && _weekendStart.TryGetValue(region!, out var start)) { startDay = start; } else { - startDay = _weekendStart!.TryGetValue("001", out var defaultStart) ? defaultStart : "sat"; + startDay = _weekendStart.TryGetValue("001", out var defaultStart) ? defaultStart : "sat"; } - if (!string.IsNullOrEmpty(region) && _weekendEnd!.TryGetValue(region!, out var end)) + if (!string.IsNullOrEmpty(region) && _weekendEnd.TryGetValue(region!, out var end)) { endDay = end; } else { - endDay = _weekendEnd!.TryGetValue("001", out var defaultEnd) ? defaultEnd : "sun"; + endDay = _weekendEnd.TryGetValue("001", out var defaultEnd) ? defaultEnd : "sun"; } var startNum = DayNameToNumber(startDay); @@ -173,82 +129,4 @@ private static int DayNameToNumber(string dayName) }; } - private static void EnsureLoaded() - { - if (_loaded) - { - return; - } - - lock (_lock) - { - if (_loaded) - { - return; - } - - _firstDay = new Dictionary(StringComparer.OrdinalIgnoreCase); - _minDays = new Dictionary(StringComparer.OrdinalIgnoreCase); - _weekendStart = new Dictionary(StringComparer.OrdinalIgnoreCase); - _weekendEnd = new Dictionary(StringComparer.OrdinalIgnoreCase); - - var assembly = typeof(WeekData).Assembly; - using var stream = assembly.GetManifestResourceStream("Jint.Native.Intl.Data.WeekData.txt"); - if (stream is null) - { - _loaded = true; - return; - } - - using var reader = new StreamReader(stream); - string? currentSection = null; - - while (reader.ReadLine() is { } line) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - if (line.Length > 2 && line[0] == '[' && line[line.Length - 1] == ']') - { - currentSection = line.Substring(1, line.Length - 2); - continue; - } - - var eqIndex = line.IndexOf('='); - if (eqIndex < 0) - { - continue; - } - - var key = line.Substring(0, eqIndex); - var value = line.Substring(eqIndex + 1); - - switch (currentSection) - { - case "FIRST_DAY": - _firstDay[key] = value; - break; - - case "MIN_DAYS": - if (int.TryParse(value, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out var minDays)) - { - _minDays[key] = minDays; - } - break; - - case "WEEKEND_START": - _weekendStart[key] = value; - break; - - case "WEEKEND_END": - _weekendEnd[key] = value; - break; - } - } - - _loaded = true; - } - } }