### Format Dates and Times with NLS Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Demonstrates how to format a DateTime object using various standard date and time formats across different cultures with National Language Support enabled. Ensure the Codebelt.Extensions.Globalization NuGet package is installed. ```csharp using System; using System.Globalization; using Codebelt.Extensions.Globalization; DateTime date = new DateTime(2024, 6, 7, 14, 30, 0); var cultures = new[] { new CultureInfo("en-US"), new CultureInfo("de-DE"), new CultureInfo("ar-SA"), new CultureInfo("ja-JP") }; foreach (var cultureName in cultures) { var culture = cultureName.UseNationalLanguageSupport(); Console.WriteLine($"\n{culture.Name} ({culture.EnglishName}):"); Console.WriteLine($" Short Date: {date:d}"); Console.WriteLine($" Long Date: {date:D}"); Console.WriteLine($" Short Time: {date:t}"); Console.WriteLine($" Long Time: {date:T}"); Console.WriteLine($" Full Date/Time: {date:f}"); } // Output examples: // en-US (English - United States): // Short Date: 6/7/2024 // Long Date: Friday, June 7, 2024 // Short Time: 2:30 PM // Long Time: 2:30:00 PM // Full Date/Time: Friday, June 7, 2024 2:30 PM // // de-DE (German - Germany): // Short Date: 07.06.2024 // Long Date: Freitag, 7. Juni 2024 // Short Time: 14:30 // Long Time: 14:30:00 // Full Date/Time: Freitag, 7. Juni 2024 14:30 ``` -------------------------------- ### Format Currency with NLS Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Format currency values using the 'C' format specifier with NLS-enriched cultures. This example shows how currency symbols and decimal separators vary across different regions. ```csharp using System; using System.Globalization; using Codebelt.Extensions.Globalization; decimal price = 19.99m; CultureInfo usEnglish = new CultureInfo("en-US").UseNationalLanguageSupport(); CultureInfo europeEuro = new CultureInfo("de-DE").UseNationalLanguageSupport(); CultureInfo ukEnglish = new CultureInfo("en-GB").UseNationalLanguageSupport(); Console.WriteLine(price.ToString("C", usEnglish)); // $19.99 Console.WriteLine(price.ToString("C", europeEuro)); // 19,99 € Console.WriteLine(price.ToString("C", ukEnglish)); // £19.99 ``` -------------------------------- ### NLS Data Format Example (YAML) Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/nls-vs-icu.md Illustrates the structure of NLS data stored in YAML format, including date and number formatting properties. This format is serialized to GZIP-compressed binary files. ```yaml DateTimeFormat: AMDesignator: "AM" PMDesignator: "PM" DateSeparator: "/" TimeSeparator: ":" FullDateTimePattern: "dddd, d MMMM yyyy HH:mm:ss" LongDatePattern: "dddd, d MMMM yyyy" ShortDatePattern: "d/M/yyyy" LongTimePattern: "HH:mm:ss" ShortTimePattern: "HH:mm" MonthDayPattern: "d MMMM" YearMonthPattern: "MMMM yyyy" FirstDayOfWeek: "Monday" CalendarWeekRule: "FirstDay" DayNames: ["Monday", "Tuesday", ...] AbbreviatedDayNames: ["Mon", "Tue", ...] MonthNames: ["January", "February", ...] AbbreviatedMonthNames: ["Jan", "Feb", ...] NumberFormat: CurrencySymbol: "$" CurrencyDecimalDigits: 2 CurrencyDecimalSeparator: "." CurrencyGroupSeparator: "," CurrencyNegativePattern: 0 CurrencyPositivePattern: 0 NumberDecimalDigits: 2 NumberDecimalSeparator: "." NumberGroupSeparator: "," NumberNegativePattern: 1 PercentSymbol: "%" PercentDecimalDigits: 2 # ... and 10+ more currency/number format properties ``` -------------------------------- ### CultureInfoExtensions.UseNationalLanguageSupport(IEnumerable) Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/INDEX.txt Enriches a collection of CultureInfo objects with national language support details. Includes full signature, return type, exception catalog, and usage example. ```APIDOC ## UseNationalLanguageSupport(IEnumerable) ### Description Enriches a collection of CultureInfo objects with national language support details. ### Method [Method Signature] ### Parameters #### Path Parameters - **cultures** (IEnumerable) - Required - The collection of CultureInfo objects to enrich. ### Response #### Success Response - **IEnumerable** - The collection of enriched CultureInfo objects. ### Error Handling - **ArgumentNullException**: Trigger conditions and locations. - **InvalidOperationException**: Trigger conditions and handling. ``` -------------------------------- ### CultureInfoExtensions.UseNationalLanguageSupport(CultureInfo) Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/INDEX.txt Enriches a single CultureInfo object with national language support details. Includes full signature, return type, exception catalog, and usage example. ```APIDOC ## UseNationalLanguageSupport(CultureInfo) ### Description Enriches a single CultureInfo object with national language support details. ### Method [Method Signature] ### Parameters #### Path Parameters - **culture** (CultureInfo) - Required - The CultureInfo object to enrich. ### Response #### Success Response - **CultureInfo** - The enriched CultureInfo object. ### Error Handling - **ArgumentNullException**: Trigger conditions and locations. - **InvalidOperationException**: Trigger conditions and handling. ``` -------------------------------- ### YAML Structure for Culture Information Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md Example of the expected YAML format for storing culture information, including DateTimeFormat and NumberFormat details. This structure is used for binary embedded resources after GZIP compression. ```yaml # Expected format in binary YAML files DateTimeFormat: AMDesignator: "AM" PMDesignator: "PM" DateSeparator: "/" TimeSeparator: ":" FirstDayOfWeek: 0 # DayOfWeek enum value CalendarWeekRule: 0 # CalendarWeekRule enum value FullDateTimePattern: "dddd, d MMMM yyyy HH:mm:ss" LongDatePattern: "dddd, d MMMM yyyy" ShortDatePattern: "d/M/yyyy" LongTimePattern: "HH:mm:ss" ShortTimePattern: "HH:mm" MonthDayPattern: "d MMMM" YearMonthPattern: "MMMM yyyy" ShortestDayNames: ["S", "M", "T", "W", "T", "F", "S"] AbbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] AbbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""] AbbreviatedMonthGenitiveNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""] NumberFormat: CurrencyDecimalDigits: 2 CurrencyDecimalSeparator: "." CurrencyGroupSeparator: "," CurrencySymbol: "$" CurrencyNegativePattern: 0 CurrencyPositivePattern: 0 DigitSubstitution: 1 # DigitShapes enum value NaNSymbol: "NaN" NegativeInfinitySymbol: "-Infinity" NegativeSign: "-" NumberDecimalDigits: 2 NumberDecimalSeparator: "." NumberGroupSeparator: "," NumberNegativePattern: 1 PercentDecimalDigits: 2 PercentDecimalSeparator: "." PercentGroupSeparator: "," PercentNegativePattern: 0 PercentPositivePattern: 0 PercentSymbol: "%" PerMilleSymbol: "‰" PositiveInfinitySymbol: "Infinity" PositiveSign: "+" ``` -------------------------------- ### Run DocFX Verification Commands Source: https://github.com/codebeltnet/globalization/blob/main/AGENTS.md Execute these commands to verify documentation builds and sample integrity. Ensure all prerequisites are met before running. ```bash dotnet build dotnet test dotnet run --file /scripts/docfx.cs -- --repo-root . --build-api-model --validate-samples --verify-docfx-build ``` -------------------------------- ### Bulk Enrich Cultures at Application Startup Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Initialize a collection of commonly used cultures with national language support during application startup. This ensures fast lookups later in the application lifecycle. ```csharp using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using Codebelt.Extensions.Globalization; // During application startup, pre-enrich cultures you know you'll use class CultureManager { private static Dictionary _supportedCultures; public static void Initialize(params string[] cultureNames) { _supportedCultures = cultureNames .Select(name => new CultureInfo(name)) .UseNationalLanguageSupport() .ToDictionary(c => c.Name, StringComparer.Ordinal); Console.WriteLine($"Initialized {_supportedCultures.Count} cultures with NLS support"); } public static CultureInfo GetCulture(string name) { return _supportedCultures.ContainsKey(name) ? _supportedCultures[name] : CultureInfo.InvariantCulture; } } // Startup code CultureManager.Initialize("en-US", "de-DE", "fr-FR", "ja-JP", "es-ES"); // Later in application var culture = CultureManager.GetCulture("de-DE"); // Instant lookup ``` -------------------------------- ### Cache Optimization: GetOrAdd vs. TryGetValue + TryAdd Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md Compares the current two-step cache retrieval and addition pattern with the more concise one-step GetOrAdd method. GetOrAdd can reduce duplicate work but introduces complexity. ```csharp // Current (two-step): if (!cache.TryGetValue(key, out var value)) { value = expensive(); cache.TryAdd(key, value); } ``` ```csharp // Alternative (one-step): var value = cache.GetOrAdd(key, _ => expensive()); ``` -------------------------------- ### Safely Get Enriched Culture Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Use this method to safely retrieve a CultureInfo object, falling back to the invariant culture if the specified culture is unsupported or invalid. It handles InvalidOperationException and ArgumentNullException. ```csharp using System; using System.Globalization; using Codebelt.Extensions.Globalization; static CultureInfo GetEnrichedCultureSafely(string cultureName) { try { var culture = new CultureInfo(cultureName); return culture.UseNationalLanguageSupport(); } catch (InvalidOperationException ex) { Console.WriteLine($"Culture {cultureName} is not supported: {ex.Message}"); // Fall back to invariant culture return CultureInfo.InvariantCulture; } catch (ArgumentNullException ex) { Console.WriteLine($"Invalid culture parameter: {ex.ParamName}"); return CultureInfo.InvariantCulture; } } // Usage var culture = GetEnrichedCultureSafely("xx-YY"); // Unsupported Console.WriteLine($"Using culture: {culture.Name}"); // Output: Using culture: ``` -------------------------------- ### Build and Test Without Strong-Name Signing Source: https://github.com/codebeltnet/globalization/blob/main/AGENTS.md Use this flag when building or testing if the repository lacks a root .snk file. This bypasses assembly signing. ```bash dotnet build -p:SkipSignAssembly=true ``` ```bash dotnet test -p:SkipSignAssembly=true ``` -------------------------------- ### Natural Syntax for Culture Enrichment Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/README.md Demonstrates the natural syntax for enriching a single culture using the UseNationalLanguageSupport extension method. ```csharp // Natural syntax: var enriched = culture.UseNationalLanguageSupport(); ``` -------------------------------- ### Demonstrate CultureInfo Caching Behavior Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Illustrates the caching mechanism for CultureInfo objects. The first call results in a cache miss and full processing, while subsequent calls with the same culture code hit the cache and return the identical CultureInfo object immediately. ```csharp // First call: cache miss, full pipeline var enUs1 = new CultureInfo("en-US").UseNationalLanguageSupport(); // Second call: cache hit, returns immediately var enUs2 = new CultureInfo("en-US").UseNationalLanguageSupport(); // enUs1 and enUs2 are the same object from the cache ``` -------------------------------- ### Potential Reflection-Based Property Assignment Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md Discusses the possibility of using PropertyInfo[] for dynamic property assignment. This approach is not favored due to slower performance, reduced clarity, and similar resource usage compared to other methods. ```csharp // Could use PropertyInfo[] to assign dynamically // But: Slower, less clear, same resource usage ``` -------------------------------- ### Format Day and Month Names with NLS Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Shows how to retrieve and display day names and month names for a specific culture using National Language Support. This is useful for building localized UI elements. ```csharp using System; using System.Globalization; using Codebelt.Extensions.Globalization; var culture = new CultureInfo("es-ES").UseNationalLanguageSupport(); var dateTimeFormat = culture.DateTimeFormat; Console.WriteLine("Day Names:"); foreach (var dayName in dateTimeFormat.DayNames) Console.WriteLine($" {dayName}"); Console.WriteLine("\nMonth Names:"); foreach (var monthName in dateTimeFormat.MonthNames.Take(12)) Console.WriteLine($" {monthName}"); // Output: // Day Names: // domingo // lunes // martes // miércoles // jueves // viernes // sábado // // Month Names: // enero // febrero // marzo // ... ``` -------------------------------- ### Format Price and Date with User Culture Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Formats currency and dates based on a specified user culture. Handles unsupported cultures by falling back to the current culture. ```csharp using System; using System.Globalization; using Codebelt.Extensions.Globalization; class LocalizationService { public string FormatPrice(decimal amount, string userCultureName) { try { var culture = new CultureInfo(userCultureName) .UseNationalLanguageSupport(); return amount.ToString("C", culture); } catch (InvalidOperationException) { // Culture not supported, use default return amount.ToString("C", CultureInfo.CurrentCulture); } } public string FormatDate(DateTime date, string userCultureName) { try { var culture = new CultureInfo(userCultureName) .UseNationalLanguageSupport(); return date.ToString("D", culture); } catch (InvalidOperationException) { return date.ToString("D", CultureInfo.CurrentCulture); } } } // Usage var localization = new LocalizationService(); var price = localization.FormatPrice(99.99m, "de-DE"); // 99,99 € var date = localization.FormatDate(DateTime.Now, "fr-FR"); // vendredi 7 juin 2024 ``` -------------------------------- ### Initialize ConcurrentDictionary for CultureInfo Caching Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Initializes a thread-safe ConcurrentDictionary to cache CultureInfo objects. Uses ordinal string comparison for keys and has a lifespan of the application's AppDomain. Benefits include avoiding redundant culture processing and fast lookups. ```csharp private static readonly ConcurrentDictionary EnrichedCultureInfos = new(StringComparer.Ordinal); ``` -------------------------------- ### Handle Unsupported Culture Errors Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/README.md Demonstrates how to handle potential InvalidOperationException errors that may occur when attempting to enrich an unsupported culture. ```csharp try { var culture = new CultureInfo("xx-YY").UseNationalLanguageSupport(); } catch (InvalidOperationException ex) { Console.WriteLine("Culture not supported: " + ex.Message); } ``` -------------------------------- ### Use NLS with .NET Core/5+ on Windows Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/nls-vs-icu.md When migrating to .NET Core/5+ on Windows, you can use the NLS library to maintain behavior identical to .NET Framework. This ensures consistency for legacy applications. ```csharp var culture = new CultureInfo("de-DE").UseNationalLanguageSupport(); // Result: identical to .NET Framework behavior ``` -------------------------------- ### Null Resource Handling in C# Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md Demonstrates explicit checking for null values when retrieving resources. This pattern ensures that operations do not proceed with missing data, throwing a specific exception for clarity. ```csharp // Line 61-64 if (surrogate.Value is null) { throw new InvalidOperationException( $"No NLS surrogate is available for culture '{culture.Name}' ({culture.EnglishName})..."); } ``` -------------------------------- ### Clone Read-Only CultureInfo Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md Demonstrates cloning a read-only CultureInfo object to create a writable copy for modification. This is necessary because system-provided CultureInfo instances are often read-only to prevent accidental changes. ```csharp if (culture.IsReadOnly) { var cultureClone = culture.Clone() as CultureInfo; Enrich(cultureClone, surrogateCulture); } ``` ```csharp var culture = new CultureInfo("en-US"); culture.IsReadOnly // true // This would throw if read-only: culture.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd"; // Exception ``` ```csharp var cultureClone = culture.Clone() as CultureInfo; cultureClone.IsReadOnly // false (after clone) // Now we can modify culture.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd"; // OK ``` -------------------------------- ### Format Percentages with NLS Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Format decimal values as percentages using the 'P2' format specifier with NLS-enriched cultures. This illustrates how percentage symbols and decimal separators are localized. ```csharp using System; using System.Globalization; using Codebelt.Extensions.Globalization; decimal percent = 0.8765m; CultureInfo usEnglish = new CultureInfo("en-US").UseNationalLanguageSupport(); CultureInfo german = new CultureInfo("de-DE").UseNationalLanguageSupport(); Console.WriteLine(percent.ToString("P2", usEnglish)); // 87.65% Console.WriteLine(percent.ToString("P2", german)); // 87,65% ``` -------------------------------- ### Include Surrogate Files in Build Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md This MSBuild setting includes all binary surrogate files from the Surrogates directory as embedded resources. Ensure this glob pattern correctly targets your surrogate files. ```xml ``` -------------------------------- ### Composable Culture Enrichment with LINQ Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/README.md Shows how to use the UseNationalLanguageSupport extension method in a composable way with LINQ for filtering cultures. ```csharp // Composable with LINQ: var enriched = cultures .UseNationalLanguageSupport() .Where(c => c.Name.StartsWith("en-")) .ToList(); ``` -------------------------------- ### Potential Parallel Enumeration Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md Illustrates the theoretical possibility of using Parallel.ForEach for enumeration. However, this is not implemented due to potential loss of lazy evaluation and unnecessary complexity for typical workloads. ```csharp // Could theoretically use Parallel.ForEach // But: Loss of lazy evaluation, unnecessary for typical workloads ``` -------------------------------- ### Load Embedded Resource for Culture Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Uses reflection to find and load an embedded resource file named '{culture.Name}.bin'. The resource is matched if its name contains the culture name. ```csharp var surrogate = typeof(CultureInfoExtensions) .GetEmbeddedResources($"{culture.Name}.bin", ManifestResourceMatch.ContainsName) .SingleOrDefault(); ``` -------------------------------- ### Handling InvalidOperationException by Checking Support Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/errors.md Shows how to validate if a culture is supported before attempting to enrich it with national language support. This prevents exceptions and allows for graceful fallback. ```csharp CultureInfo culture = new CultureInfo("my-test"); try { var enriched = culture.UseNationalLanguageSupport(); } catch (InvalidOperationException) { // Fall back to default ICU-based formatting Console.WriteLine($"Culture {culture.Name} not supported, using default."); } ``` -------------------------------- ### Use NLS for Legacy .NET Framework Apps Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/nls-vs-icu.md Use this for legacy .NET Framework applications that require existing NLS-based formatting or need to match Windows system settings for enterprise/business users. It ensures backward compatibility and handles subtle regional formatting differences. ```csharp // Legacy application expecting NLS behavior var culture = new CultureInfo("de-DE").UseNationalLanguageSupport(); var amount = 1234.56m.ToString("C", culture); // Windows-style currency ``` -------------------------------- ### NumberFormatInfoSurrogate Structure Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Mirrors the structure of System.Globalization.NumberFormatInfo, storing number, currency, and percentage formatting rules. Includes a copy constructor for populating from live NumberFormatInfo objects. ```csharp public NumberFormatInfoSurrogate(NumberFormatInfo info) ``` -------------------------------- ### Initialize ConcurrentDictionary for Caching Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md Initializes a thread-safe ConcurrentDictionary for caching CultureInfo objects. It uses StringComparer.Ordinal for case-sensitive, culture-independent key comparisons, eliminating the need for explicit locking. ```csharp // Location: CultureInfoExtensions.cs:22 private static readonly ConcurrentDictionary EnrichedCultureInfos = new(StringComparer.Ordinal); ``` -------------------------------- ### Euro Currency Formatting: NLS vs ICU Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/nls-vs-icu.md Compares currency formatting for the Euro (de-DE) between Windows NLS and ICU. Highlights differences in group separators and positive/negative patterns. ```text Symbol: € Decimal Digits: 2 Decimal Sep: , Group Sep: . Positive Pattern: +199,99 € Negative Pattern: -199,99 € ``` ```text Symbol: € Decimal Digits: 2 Decimal Sep: , Group Sep: . (or space, depending on version) Positive Pattern: 199,99 € Negative Pattern: -199,99 € (or variant) ``` -------------------------------- ### Lazy Enumeration of Enriched Cultures Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/README.md Illustrates lazy enumeration of enriched cultures, where enrichment only occurs for the first accessed culture, improving performance for large collections. ```csharp var enriched = cultures.UseNationalLanguageSupport(); var first = enriched.First(); // Only enriches first culture ``` -------------------------------- ### Catch ArgumentNullException for CultureInfo Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/errors.md Demonstrates how to catch an ArgumentNullException when a null CultureInfo is passed to UseNationalLanguageSupport. Ensure the culture parameter is not null. ```csharp using System; using System.Globalization; using Codebelt.extensions.globalization; try { CultureInfo culture = null; var enriched = culture.UseNationalLanguageSupport(); } catch (ArgumentNullException ex) { Console.WriteLine($"Culture parameter cannot be null: {ex.ParamName}"); } ``` -------------------------------- ### Catch ArgumentNullException for IEnumerable Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/errors.md Shows how to catch an ArgumentNullException when a null IEnumerable is passed to UseNationalLanguageSupport. Validate that the cultures enumerable is not null. ```csharp using System; using System.Globalization; using Codebelt.extensions.globalization; try { IEnumerable cultures = null; var enriched = cultures.UseNationalLanguageSupport().ToList(); } catch (ArgumentNullException ex) { Console.WriteLine($"Cultures enumerable cannot be null: {ex.ParamName}"); } ``` -------------------------------- ### Catching InvalidOperationException for Unsupported Cultures Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/errors.md Demonstrates how to catch an InvalidOperationException when attempting to use national language support for an unsupported culture. This is useful for providing user feedback or alternative logic. ```csharp using System; using System.Globalization; using Codebelt.Extensions.Globalization; try { CultureInfo unsupported = new CultureInfo("xx-YY"); var enriched = unsupported.UseNationalLanguageSupport(); } catch (InvalidOperationException ex) { if (ex.Message.Contains("No NLS surrogate is available")) { Console.WriteLine("This culture is not supported by the library."); Console.WriteLine(ex.Message); } } ``` -------------------------------- ### DateTimeFormatInfoSurrogate Structure Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Mirrors the structure of System.Globalization.DateTimeFormatInfo, storing date and time formatting patterns and symbols. Includes a copy constructor for populating from live DateTimeFormatInfo objects. ```csharp public DateTimeFormatInfoSurrogate(DateTimeFormatInfo info) ``` -------------------------------- ### Apply DateTimeFormat Properties Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Assigns various `DateTimeFormat` properties from the surrogate culture to the target culture, including AM/PM designators, date separators, and full date/time patterns. ```csharp culture.DateTimeFormat.AMDesignator = surrogate.DateTimeFormat.AMDesignator; culture.DateTimeFormat.DateSeparator = surrogate.DateTimeFormat.DateSeparator; culture.DateTimeFormat.FullDateTimePattern = surrogate.DateTimeFormat.FullDateTimePattern; // ... 15 more properties ``` -------------------------------- ### Use National Language Support for Multiple CultureInfo Objects Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/INDEX.txt Enriches a collection of CultureInfo objects with national language support data. This method is efficient for batch operations. ```csharp public static IEnumerable UseNationalLanguageSupport(this IEnumerable cultureInfos) ``` -------------------------------- ### Use National Language Support for a Single CultureInfo Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/INDEX.txt Enriches a single CultureInfo object with national language support data. Ensure the CultureInfo object is valid. ```csharp public static CultureInfo UseNationalLanguageSupport(this CultureInfo cultureInfo) ``` -------------------------------- ### Error Propagation: Missing Resource File Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Illustrates the error flow when a required resource file is missing. GetEmbeddedResources returns null, triggering a check where if the surrogate value is null, an InvalidOperationException is thrown. ```text ┌──────────────────────────┐ │ Missing Resource File │ └────────────┬─────────────┘ │ GetEmbeddedResources returns null │ Check: if (surrogate.Value is null) ▼ ┌──────────────────┐ │ InvalidOperation │ │ Exception │ └──────────────────┘ ``` -------------------------------- ### Apply NumberFormat Properties Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Assigns various `NumberFormat` properties from the surrogate culture to the target culture, including currency symbols, decimal separators, and currency patterns for negative numbers. ```csharp culture.NumberFormat.CurrencySymbol = surrogate.NumberFormat.CurrencySymbol; culture.NumberFormat.NumberDecimalSeparator = surrogate.NumberFormat.NumberDecimalSeparator; culture.NumberFormat.CurrencyNegativePattern = surrogate.NumberFormat.CurrencyNegativePattern; // ... 20 more properties ``` -------------------------------- ### Streaming Culture Formatting Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Processes and formats data for specific cultures one at a time using streaming. This avoids buffering and is suitable for scenarios where data is processed on-demand, like in web requests. ```csharp using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using Codebelt.extensions.globalization; // Process cultures one at a time without buffering var targetCultures = new[] { "en-US", "de-DE", "fr-FR", "ja-JP", "zh-CN" }; // This processes on-demand as you iterate var enriched = targetCultures .Select(name => new CultureInfo(name)) .UseNationalLanguageSupport(); // Process each culture as it's enriched foreach (var culture in enriched) { // Each culture is enriched here, one at a time decimal price = 99.99m; Console.WriteLine($"{culture.Name}: {price.ToString("C", culture)}"); } // Output: // en-US: $99.99 // de-DE: 99,99 € // fr-FR: 99,99 € // ja-JP: ¥99.99 // zh-CN: ¥99.99 ``` -------------------------------- ### Lazy Enumeration for CultureInfo Collections Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md This enumerable extension method provides lazy evaluation using 'yield return', enriching cultures on-demand as iteration occurs. It is memory-efficient for large collections and allows for early exit. ```csharp public static IEnumerable UseNationalLanguageSupport( this IEnumerable cultures) { foreach (var culture in cultures) { // ... processing ... yield return enrichedCulture; // Lazy evaluation } } ``` ```csharp var cultures = new[] { new CultureInfo("en-US"), new CultureInfo("de-DE"), new CultureInfo("fr-FR") }; // This doesn't enrich anything yet var enriched = cultures.UseNationalLanguageSupport(); // Enrichment happens here, one at a time var first = enriched.First(); // Only en-US enriched // Only continue if needed var enOnly = enriched.Where(c => c.Name.StartsWith("en-")).ToList(); // Only enrich en-* cultures ``` -------------------------------- ### Check Cache for Enriched Culture Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Checks a thread-safe cache (`EnrichedCultureInfos`) for a pre-enriched CultureInfo. If found, it's returned immediately via `yield return` for the fast path. ```csharp if (EnrichedCultureInfos.TryGetValue(culture.Name, out var enrichedCulture)) { yield return enrichedCulture; // Cache hit - fast path } ``` -------------------------------- ### Use National Language Support with CultureInfo Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/nls-vs-icu.md Enriches a CultureInfo object with National Language Support data, enabling consistent formatting across different platforms. This process involves cache lookups, embedded resource decompression, deserialization, and applying properties to DateTimeFormat and NumberFormat. ```csharp var culture = new CultureInfo("de-DE").UseNationalLanguageSupport(); // Steps: // 1. Check cache for "de-DE" (miss on first call) // 2. Find embedded resource "de-DE.bin" // 3. Decompress GZIP data // 4. Deserialize YAML to CultureInfoSurrogate // 5. Apply properties to CultureInfo.DateTimeFormat // 6. Apply properties to CultureInfo.NumberFormat // 7. Cache for future use // 8. Return enriched culture ``` -------------------------------- ### Enrich and Cache Read-Only Culture Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Handles read-only cultures by cloning them, enriching the clone, caching it, and then yielding the enriched clone. This preserves the immutability of the original input. ```csharp if (culture.IsReadOnly) { var cultureClone = culture.Clone() as CultureInfo; Enrich(cultureClone, surrogateCulture); EnrichedCultureInfos.TryAdd(cultureClone!.Name, cultureClone); yield return cultureClone; } ``` -------------------------------- ### Batch Culture Enrichment with Partial Failure Handling Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/errors.md This pattern processes multiple culture names in a batch, allowing for partial success. It yields results for each culture, indicating success or the specific exception encountered. ```csharp public static IEnumerable<(string name, CultureInfo enriched, Exception error)> EnrichCulturesBatch(params string[] cultureNames) { foreach (var name in cultureNames) { Exception error = null; CultureInfo enriched = null; try { enriched = new CultureInfo(name).UseNationalLanguageSupport(); } catch (Exception ex) { error = ex; } yield return (name, enriched, error); } } // Usage var results = EnrichCulturesBatch("en-US", "de-DE", "xx-YY"); foreach (var (name, culture, error) in results) { if (error == null) Console.WriteLine($"✓ {name}: Enriched successfully"); else Console.WriteLine($"✗ {name}: {error.Message}"); } ``` -------------------------------- ### Use National Language Support Extension Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md This extension method enriches a CultureInfo object with National Language Support data. It utilizes a cache for performance and loads data from embedded resources. ```csharp var enriched = culture.UseNationalLanguageSupport() ``` -------------------------------- ### UseNationalLanguageSupport (Collection) Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/api-reference.md Enriches a sequence of CultureInfo objects with Windows NLS formatting data. This method processes collections lazily and applies NLS enrichment to each culture. ```APIDOC ## UseNationalLanguageSupport (Collection) ### Description Enriches a sequence of `CultureInfo` objects with Windows NLS formatting data. ### Method `public static IEnumerable UseNationalLanguageSupport(this IEnumerable cultures)` ### Parameters #### Path Parameters - **cultures** (IEnumerable) - Required - The sequence of cultures to enrich with NLS data ### Return Type `IEnumerable` - A lazy-evaluated sequence of enriched culture objects. Each culture in the input sequence is yielded after NLS enrichment has been applied. ### Throws - `ArgumentNullException` - `cultures` parameter is null - `InvalidOperationException` - No embedded NLS surrogate resource is available for one or more cultures in the sequence ### Remarks This is the overload method that processes collections. It internally checks the enriched cultures cache, loads and decompresses embedded resources, deserializes binary data, applies surrogate data to a clone or original culture, and caches the result. The implementation uses `YamlDotNet` to deserialize the binary NLS data. ### Usage Example ```csharp using System.Globalization; using System.Linq; using Codebelt.Extensions.Globalization; // Enrich multiple cultures at once var cultures = new[] { new CultureInfo("en-US"), new CultureInfo("de-DE"), new CultureInfo("fr-FR") }; var enrichedCultures = cultures.UseNationalLanguageSupport().ToList(); foreach (var culture in enrichedCultures) { Console.WriteLine($"{culture.Name}: {culture.DateTimeFormat.ShortDatePattern}"); } ``` ``` -------------------------------- ### Enrich and Cache Writable Culture Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Handles writable cultures by enriching them in-place, caching the modified original culture, and then yielding it. This modifies the original object. ```csharp else { Enrich(culture, surrogateCulture); EnrichedCultureInfos.TryAdd(culture.Name, culture); yield return culture; } ``` -------------------------------- ### Iterate and Yield Enriched Cultures Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/architecture.md Uses `yield return` for lazy enumeration of enriched cultures, allowing for efficient processing of large collections. ```csharp foreach (var culture in cultures) // Line 52 { // ... enrichment logic ... yield return enrichedCulture; // Lazy evaluation } ``` -------------------------------- ### Add CultureInfo to Cache Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/internals.md Adds a CultureInfo object to the ConcurrentDictionary cache using TryAdd. This method is atomic and thread-safe, ensuring that duplicate keys are handled gracefully without explicit locking. ```csharp // Line 77 (read-only culture) EnrichedCultureInfos.TryAdd(cultureClone!.Name, cultureClone); // Line 83 (writable culture) EnrichedCultureInfos.TryAdd(culture.Name, culture); ``` -------------------------------- ### Enrich Multiple Cultures with NLS Data Source: https://github.com/codebeltnet/globalization/blob/main/_autodocs/usage-examples.md Enrich a collection of `CultureInfo` objects simultaneously using `UseNationalLanguageSupport`. This is efficient when you need to apply NLS formatting across several cultures for consistent output. ```csharp using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using Codebelt.Extensions.Globalization; // Create multiple cultures var cultures = new List { new CultureInfo("en-US"), new CultureInfo("de-DE"), new CultureInfo("fr-FR"), new CultureInfo("ja-JP") }; // Enrich all at once var enrichedCultures = cultures.UseNationalLanguageSupport().ToList(); // Use them for formatting foreach (var culture in enrichedCultures) { string formatted = DateTime.Now.ToString("D", culture); Console.WriteLine($"{culture.Name}: {formatted}"); } // Output: // en-US: Saturday, June 7, 2024 // de-DE: Samstag, 7. Juni 2024 // fr-FR: samedi 7 juin 2024 // ja-JP: 2024年6月7日 ```