diff --git a/src/Codebelt.Extensions.Globalization/Codebelt.Extensions.Globalization.csproj b/src/Codebelt.Extensions.Globalization/Codebelt.Extensions.Globalization.csproj index 34ff398..d8737d4 100644 --- a/src/Codebelt.Extensions.Globalization/Codebelt.Extensions.Globalization.csproj +++ b/src/Codebelt.Extensions.Globalization/Codebelt.Extensions.Globalization.csproj @@ -1223,6 +1223,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Codebelt.Extensions.Globalization/CultureInfoExtensions.cs b/src/Codebelt.Extensions.Globalization/CultureInfoExtensions.cs index 55ea34e..b3b6543 100644 --- a/src/Codebelt.Extensions.Globalization/CultureInfoExtensions.cs +++ b/src/Codebelt.Extensions.Globalization/CultureInfoExtensions.cs @@ -58,6 +58,10 @@ public static IEnumerable UseNationalLanguageSupport(this IEnumerab else { var surrogate = typeof(CultureInfoExtensions).GetEmbeddedResources($"{culture.Name}.bin", ManifestResourceMatch.ContainsName).SingleOrDefault(); + if (surrogate.Value is null) + { + throw new InvalidOperationException($"No NLS surrogate is available for culture '{culture.Name}' ({culture.EnglishName}). Ensure the embedded resource '{culture.Name}.bin' has been generated by the gse tooling and included as an EmbeddedResource in the assembly."); + } var ms = new MemoryStream(surrogate.Value.DecompressGZip().ToByteArray()); var surrogateCulture = YamlFormatter.DeserializeObject(ms, o => { diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ar-eh.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ar-eh.bin new file mode 100644 index 0000000..86931e8 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ar-eh.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/bgc-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/bgc-in.bin new file mode 100644 index 0000000..b6acdbd Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/bgc-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/bho-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/bho-in.bin new file mode 100644 index 0000000..50c0552 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/bho-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/blo-bj.bin b/src/Codebelt.Extensions.Globalization/Surrogates/blo-bj.bin new file mode 100644 index 0000000..a566078 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/blo-bj.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/bm-ml.bin b/src/Codebelt.Extensions.Globalization/Surrogates/bm-ml.bin new file mode 100644 index 0000000..ec29eff Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/bm-ml.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ca-es-valencia.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ca-es-valencia.bin new file mode 100644 index 0000000..0c39431 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ca-es-valencia.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ccp-bd.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ccp-bd.bin new file mode 100644 index 0000000..5ddbac4 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ccp-bd.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ccp-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ccp-in.bin new file mode 100644 index 0000000..c2be0b7 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ccp-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ceb-ph.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ceb-ph.bin new file mode 100644 index 0000000..2145fd4 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ceb-ph.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/chr-us.bin b/src/Codebelt.Extensions.Globalization/Surrogates/chr-us.bin new file mode 100644 index 0000000..b413c76 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/chr-us.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ckb-iq.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ckb-iq.bin new file mode 100644 index 0000000..d0c02a8 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ckb-iq.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ckb-ir.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ckb-ir.bin new file mode 100644 index 0000000..76d96c8 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ckb-ir.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/csw-ca.bin b/src/Codebelt.Extensions.Globalization/Surrogates/csw-ca.bin new file mode 100644 index 0000000..8a00519 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/csw-ca.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/cv-ru.bin b/src/Codebelt.Extensions.Globalization/Surrogates/cv-ru.bin new file mode 100644 index 0000000..5162fce Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/cv-ru.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/doi-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/doi-in.bin new file mode 100644 index 0000000..5575881 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/doi-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/en-dg.bin b/src/Codebelt.Extensions.Globalization/Surrogates/en-dg.bin new file mode 100644 index 0000000..16fbdd3 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/en-dg.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/en-us-posix.bin b/src/Codebelt.Extensions.Globalization/Surrogates/en-us-posix.bin new file mode 100644 index 0000000..af5253f Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/en-us-posix.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/es-ea.bin b/src/Codebelt.Extensions.Globalization/Surrogates/es-ea.bin new file mode 100644 index 0000000..518f817 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/es-ea.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/es-ic.bin b/src/Codebelt.Extensions.Globalization/Surrogates/es-ic.bin new file mode 100644 index 0000000..518f817 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/es-ic.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ha-gh.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ha-gh.bin new file mode 100644 index 0000000..9cfe185 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ha-gh.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ha-ne.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ha-ne.bin new file mode 100644 index 0000000..7f2170e Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ha-ne.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ha-ng.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ha-ng.bin new file mode 100644 index 0000000..0f98b18 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ha-ng.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ie-ee.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ie-ee.bin new file mode 100644 index 0000000..40817fb Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ie-ee.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/iu-ca.bin b/src/Codebelt.Extensions.Globalization/Surrogates/iu-ca.bin new file mode 100644 index 0000000..bc9673a Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/iu-ca.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/jv-id.bin b/src/Codebelt.Extensions.Globalization/Surrogates/jv-id.bin new file mode 100644 index 0000000..a534a71 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/jv-id.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/kgp-br.bin b/src/Codebelt.Extensions.Globalization/Surrogates/kgp-br.bin new file mode 100644 index 0000000..42c9c68 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/kgp-br.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ko-cn.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ko-cn.bin new file mode 100644 index 0000000..9802e6a Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ko-cn.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/ku-tr.bin b/src/Codebelt.Extensions.Globalization/Surrogates/ku-tr.bin new file mode 100644 index 0000000..dcd95cd Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/ku-tr.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/kxv-deva-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/kxv-deva-in.bin new file mode 100644 index 0000000..72d3f24 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/kxv-deva-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/kxv-latn-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/kxv-latn-in.bin new file mode 100644 index 0000000..a836a32 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/kxv-latn-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/kxv-orya-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/kxv-orya-in.bin new file mode 100644 index 0000000..a10fc8b Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/kxv-orya-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/kxv-telu-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/kxv-telu-in.bin new file mode 100644 index 0000000..8445d8d Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/kxv-telu-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/lij-it.bin b/src/Codebelt.Extensions.Globalization/Surrogates/lij-it.bin new file mode 100644 index 0000000..e79c879 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/lij-it.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/lmo-it.bin b/src/Codebelt.Extensions.Globalization/Surrogates/lmo-it.bin new file mode 100644 index 0000000..e79c879 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/lmo-it.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/mni-beng-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/mni-beng-in.bin new file mode 100644 index 0000000..befd5db Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/mni-beng-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/pa-guru-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/pa-guru-in.bin new file mode 100644 index 0000000..0a1b81d Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/pa-guru-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/pcm-ng.bin b/src/Codebelt.Extensions.Globalization/Surrogates/pcm-ng.bin new file mode 100644 index 0000000..f5991f4 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/pcm-ng.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/prg-pl.bin b/src/Codebelt.Extensions.Globalization/Surrogates/prg-pl.bin new file mode 100644 index 0000000..837ba45 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/prg-pl.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/qu-bo.bin b/src/Codebelt.Extensions.Globalization/Surrogates/qu-bo.bin new file mode 100644 index 0000000..99c3943 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/qu-bo.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/qu-ec.bin b/src/Codebelt.Extensions.Globalization/Surrogates/qu-ec.bin new file mode 100644 index 0000000..687f76b Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/qu-ec.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/qu-pe.bin b/src/Codebelt.Extensions.Globalization/Surrogates/qu-pe.bin new file mode 100644 index 0000000..ec4992d Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/qu-pe.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/quc-gt.bin b/src/Codebelt.Extensions.Globalization/Surrogates/quc-gt.bin new file mode 100644 index 0000000..0cf8b3f Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/quc-gt.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/raj-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/raj-in.bin new file mode 100644 index 0000000..c749bde Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/raj-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/sc-it.bin b/src/Codebelt.Extensions.Globalization/Surrogates/sc-it.bin new file mode 100644 index 0000000..e89854f Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/sc-it.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/sn-zw.bin b/src/Codebelt.Extensions.Globalization/Surrogates/sn-zw.bin new file mode 100644 index 0000000..bbe0602 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/sn-zw.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/syr-iq.bin b/src/Codebelt.Extensions.Globalization/Surrogates/syr-iq.bin new file mode 100644 index 0000000..6b617a2 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/syr-iq.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/szl-pl.bin b/src/Codebelt.Extensions.Globalization/Surrogates/szl-pl.bin new file mode 100644 index 0000000..9fef52d Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/szl-pl.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/tg-tj.bin b/src/Codebelt.Extensions.Globalization/Surrogates/tg-tj.bin new file mode 100644 index 0000000..391d8f6 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/tg-tj.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/tok-001.bin b/src/Codebelt.Extensions.Globalization/Surrogates/tok-001.bin new file mode 100644 index 0000000..16fbdd3 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/tok-001.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/tzm-dz.bin b/src/Codebelt.Extensions.Globalization/Surrogates/tzm-dz.bin new file mode 100644 index 0000000..132ef38 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/tzm-dz.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/tzm-ma.bin b/src/Codebelt.Extensions.Globalization/Surrogates/tzm-ma.bin new file mode 100644 index 0000000..71cd165 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/tzm-ma.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/vec-it.bin b/src/Codebelt.Extensions.Globalization/Surrogates/vec-it.bin new file mode 100644 index 0000000..e79c879 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/vec-it.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/vmw-mz.bin b/src/Codebelt.Extensions.Globalization/Surrogates/vmw-mz.bin new file mode 100644 index 0000000..92aa462 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/vmw-mz.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/xnr-in.bin b/src/Codebelt.Extensions.Globalization/Surrogates/xnr-in.bin new file mode 100644 index 0000000..72d3f24 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/xnr-in.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/yi-ua.bin b/src/Codebelt.Extensions.Globalization/Surrogates/yi-ua.bin new file mode 100644 index 0000000..9394be7 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/yi-ua.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/yrl-br.bin b/src/Codebelt.Extensions.Globalization/Surrogates/yrl-br.bin new file mode 100644 index 0000000..e174a85 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/yrl-br.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/yrl-co.bin b/src/Codebelt.Extensions.Globalization/Surrogates/yrl-co.bin new file mode 100644 index 0000000..d8ad857 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/yrl-co.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/yrl-ve.bin b/src/Codebelt.Extensions.Globalization/Surrogates/yrl-ve.bin new file mode 100644 index 0000000..16b9f30 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/yrl-ve.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/yue-hans-cn.bin b/src/Codebelt.Extensions.Globalization/Surrogates/yue-hans-cn.bin new file mode 100644 index 0000000..1fd5894 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/yue-hans-cn.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/yue-hant-hk.bin b/src/Codebelt.Extensions.Globalization/Surrogates/yue-hant-hk.bin new file mode 100644 index 0000000..bc9a66f Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/yue-hant-hk.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/za-cn.bin b/src/Codebelt.Extensions.Globalization/Surrogates/za-cn.bin new file mode 100644 index 0000000..1fd5894 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/za-cn.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/zgh-ma.bin b/src/Codebelt.Extensions.Globalization/Surrogates/zgh-ma.bin new file mode 100644 index 0000000..888972a Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/zgh-ma.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/zh-hans-cn.bin b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hans-cn.bin new file mode 100644 index 0000000..1fd5894 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hans-cn.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/zh-hans-sg.bin b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hans-sg.bin new file mode 100644 index 0000000..5abd373 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hans-sg.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-hk.bin b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-hk.bin new file mode 100644 index 0000000..bc9a66f Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-hk.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-mo.bin b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-mo.bin new file mode 100644 index 0000000..5645a5b Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-mo.bin differ diff --git a/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-tw.bin b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-tw.bin new file mode 100644 index 0000000..6915cf5 Binary files /dev/null and b/src/Codebelt.Extensions.Globalization/Surrogates/zh-hant-tw.bin differ diff --git a/test/Codebelt.Extensions.Globalization.Tests/CultureInfoExtensionsTest.cs b/test/Codebelt.Extensions.Globalization.Tests/CultureInfoExtensionsTest.cs index a4dbb42..2664ba1 100644 --- a/test/Codebelt.Extensions.Globalization.Tests/CultureInfoExtensionsTest.cs +++ b/test/Codebelt.Extensions.Globalization.Tests/CultureInfoExtensionsTest.cs @@ -1,4 +1,6 @@ -using System.Globalization; +using System; +using System.Collections.Generic; +using System.Globalization; using System.Runtime.InteropServices; using Codebelt.Extensions.Xunit; using Xunit; @@ -16,9 +18,9 @@ public void UseNationalLanguageSupport_ShouldHaveDifferentFormattingAsWindowsVar { var sut1 = new CultureInfo("da-DK", false); var sut2 = (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) - ? new CultureInfo("da-DK") // Linux uses ICU - : new CultureInfo("da-DK", false) // Ensure we do not read from user culture settings on Windows - ).UseNationalLanguageSupport(); + ? new CultureInfo("da-DK") // Linux uses ICU + : new CultureInfo("da-DK", false) // Ensure we do not read from user culture settings on Windows + ).UseNationalLanguageSupport(); Assert.NotEqual(sut1.DateTimeFormat, sut2.DateTimeFormat); Assert.NotEqual(sut1.NumberFormat, sut2.NumberFormat); @@ -106,6 +108,7 @@ public void UseNationalLanguageSupport_ShouldHaveDifferentFormattingAsWindowsVar [InlineData("byn-ER")] [InlineData("ca-AD")] [InlineData("ca-ES")] + [InlineData("ca-ES-valencia")] [InlineData("ca-FR")] [InlineData("ca-IT")] [InlineData("ccp-Cakm-BD")] @@ -722,6 +725,7 @@ public void UseNationalLanguageSupport_ShouldSucceed_ForAllSupportedLocales(stri [InlineData("byn-ER")] [InlineData("ca-AD")] [InlineData("ca-ES")] + [InlineData("ca-ES-valencia")] [InlineData("ca-FR")] [InlineData("ca-IT")] [InlineData("ccp-Cakm-BD")] @@ -1267,7 +1271,8 @@ public void UseNationalLanguageSupport_ShouldSucceed_ForAllSupportedLocales(stri [InlineData("aa-DJ")] [InlineData("aa-ER")] [InlineData("aa-ET")] - public void UseNationalLanguageSupport_ShouldSucceed_ForAllSupportedLocales_FromReadOnlyCultureInfos(string localeName) + public void UseNationalLanguageSupport_ShouldSucceed_ForAllSupportedLocales_FromReadOnlyCultureInfos( + string localeName) { var sut = CultureInfo.GetCultureInfo(localeName).UseNationalLanguageSupport(); @@ -1277,5 +1282,33 @@ public void UseNationalLanguageSupport_ShouldSucceed_ForAllSupportedLocales_From TestOutput.WriteLine($"{sut.EnglishName}/{sut.NativeName}"); } + + [Fact] + public void UseNationalLanguageSupport_EnsureAllIcuCulturesAreMapped() + { + var allCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures); + var missingIcuNames = new List(); + foreach (var culture in allCultures) + { + try + { + var sut = culture.UseNationalLanguageSupport(); + } + catch (Exception exception) + { + missingIcuNames.Add(culture.Name); + } + } + + if (missingIcuNames.Count > 0) + { + foreach (var missingIcuName in missingIcuNames) + { + + } + } + + Assert.True(missingIcuNames.Count == 0, $"The following ICU culture names were missing from the test data: {string.Join(", ", missingIcuNames)}."); + } } } diff --git a/tooling/gse/Program.cs b/tooling/gse/Program.cs index c70ca9d..b4a35e3 100644 --- a/tooling/gse/Program.cs +++ b/tooling/gse/Program.cs @@ -1,4 +1,8 @@ -using System.IO; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; using Codebelt.Extensions.Globalization; using Codebelt.Extensions.YamlDotNet.Formatters; using Cuemon.Extensions.IO; @@ -24,31 +28,165 @@ static Program() static void Main(string[] args) { - var regions = World.Regions; - foreach (var region in regions) + var cultureInfos = CultureInfo.GetCultures(CultureTypes.SpecificCultures); + foreach (var cultureInfo in cultureInfos) { - var cultureInfos = World.GetCultures(region); - foreach (var cultureInfo in cultureInfos) + WriteSurrogate(cultureInfo); + } + + WriteIcuNamedNlsAlternatives(); + } + + private static void WriteSurrogate(CultureInfo cultureInfo) + { + var dtSurrogate = new DateTimeFormatInfoSurrogate(cultureInfo.DateTimeFormat); + var nfSurrogate = new NumberFormatInfoSurrogate(cultureInfo.NumberFormat); + var ciSurrogate = new CultureInfoSurrogate(dtSurrogate, nfSurrogate); + + var ms = YamlFormatter.SerializeObject(ciSurrogate, o => + { + o.Settings.NamingConvention = NullNamingConvention.Instance; + o.Settings.ReflectionRules = new MemberReflection(); + o.Settings.IndentSequences = false; + }); + + var name = cultureInfo.Name.ToLowerInvariant(); + + using var fsRawYaml = new FileStream(Path.Combine(SurrogatesPathRaw, $"{name}.yml"), FileMode.Create); + fsRawYaml.Write(ms.ToByteArray(o => o.LeaveOpen = true), 0, (int)ms.Length); + fsRawYaml.Flush(); + + using var cms = ms.CompressGZip(); + using var fs = new FileStream(Path.Combine(SurrogatesPath, $"{name}.bin"), FileMode.Create); + fs.Write(cms.ToByteArray(o => o.LeaveOpen = true), 0, (int)cms.Length); + fs.Flush(); + } + + private static bool TryWriteNlsSurrogate(string cultureName) + { + // Attempt to resolve the culture under the current NLS runtime. + // Returns true and writes a native surrogate if Windows NLS knows the culture; + // returns false if the culture is genuinely ICU-only (CultureNotFoundException). + try + { + var ci = new CultureInfo(cultureName); + + // Guard: Windows may silently substitute InvariantCulture (LCID 0x7F) for + // unknown names instead of throwing — treat that as "not natively supported". + if (ci.LCID == CultureInfo.InvariantCulture.LCID) return false; + + // Guard: if Windows normalised the name to something else, the surrogate + // would already be covered by a different entry. + if (!ci.Name.Equals(cultureName, StringComparison.OrdinalIgnoreCase)) return false; + + if (ci.DisplayName.StartsWith("Unknown", StringComparison.OrdinalIgnoreCase)) return false; + + WriteSurrogate(ci); + return true; + } + catch (CultureNotFoundException) + { + return false; + } + } + + private static void WriteIcuNamedNlsAlternatives() + { + // Maps ICU-only culture names (absent from Windows NLS) to their nearest NLS equivalent. + // When a surrogate is written for the NLS name, a copy is also written under the ICU name + // so that ICU-based environments can resolve it from the same embedded resource set. + var icuToNls = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + // Script subtag added in NLS + { "bgc-IN", "bgc-Deva-IN" }, + { "bho-IN", "bho-Deva-IN" }, + { "bm-ML", "bm-Latn-ML" }, + { "ccp-BD", "ccp-Cakm-BD" }, + { "ccp-IN", "ccp-Cakm-IN" }, + { "ceb-PH", "ceb-Latn-PH" }, + { "chr-US", "chr-Cher-US" }, + { "cv-RU", "cv-Cyrl-RU" }, + { "doi-IN", "doi-Deva-IN" }, + { "ha-GH", "ha-Latn-GH" }, + { "ha-NE", "ha-Latn-NE" }, + { "ha-NG", "ha-Latn-NG" }, + { "iu-CA", "iu-Cans-CA" }, // ICU defaults to Unified Canadian Aboriginal Syllabics + { "jv-ID", "jv-Latn-ID" }, // ICU defaults to Latin script + { "kgp-BR", "kgp-Latn-BR" }, + { "pcm-NG", "pcm-Latn-NG" }, + { "quc-GT", "quc-Latn-GT" }, + { "raj-IN", "raj-Deva-IN" }, + { "sc-IT", "sc-Latn-IT" }, + { "sn-ZW", "sn-Latn-ZW" }, + { "tg-TJ", "tg-Cyrl-TJ" }, + { "tzm-DZ", "tzm-Latn-DZ" }, + { "tzm-MA", "tzm-Tfng-MA" }, // ICU defaults to Tifinagh script + { "yrl-BR", "yrl-Latn-BR" }, + { "yrl-CO", "yrl-Latn-CO" }, + { "yrl-VE", "yrl-Latn-VE" }, + { "zgh-MA", "zgh-Tfng-MA" }, + // Script subtag dropped in NLS + { "mni-Beng-IN", "mni-IN" }, + { "pa-Guru-IN", "pa-IN" }, + { "zh-Hans-CN", "zh-CN" }, + { "zh-Hans-SG", "zh-SG" }, + { "zh-Hant-HK", "zh-HK" }, + { "zh-Hant-MO", "zh-MO" }, + { "zh-Hant-TW", "zh-TW" }, + // Language code differs between ICU (CLDR) and NLS + { "ckb-IQ", "ku-Arab-IQ" }, // Sorani Kurdish → ku in NLS + { "ckb-IR", "ku-Arab-IR" }, + { "qu-BO", "quz-BO" }, // Quechua → quz in NLS + { "qu-EC", "quz-EC" }, + { "qu-PE", "quz-PE" }, + // POSIX variant not present in NLS + { "en-US-POSIX", "en-US" }, + // Geographic/regional fallbacks for ICU-only cultures (no NLS equivalent - Ubuntu 24.04) + { "ar-EH", "ar-MA" }, // Arabic, Western Sahara → Arabic, Morocco (nearest NLS Arabic) + { "blo-BJ", "fr-BJ" }, // Anii, Benin → French, Benin (official language) + { "csw-CA", "en-CA" }, // Swampy Cree, Canada → English, Canada + { "en-DG", "en-001" }, // English, Diego Garcia → English, World (British territory) + { "es-EA", "es-ES" }, // Spanish, Ceuta & Melilla → Spanish, Spain + { "es-IC", "es-ES" }, // Spanish, Canary Islands → Spanish, Spain + { "ie-EE", "et-EE" }, // Interlingue, Estonia → Estonian, Estonia (no NLS for Interlingue) + { "ko-CN", "ko-KR" }, // Korean, China → Korean, Korea + { "ku-TR", "tr-TR" }, // Kurdish, Turkey → Turkish, Turkey (no NLS for ku-Latn-TR) + { "kxv-Deva-IN", "hi-IN" }, // Kuvi, Devanagari → Hindi, India + { "kxv-Latn-IN", "en-IN" }, // Kuvi, Latin → English, India + { "kxv-Orya-IN", "or-IN" }, // Kuvi, Odia → Odia, India + { "kxv-Telu-IN", "te-IN" }, // Kuvi, Telugu → Telugu, India + { "lij-IT", "it-IT" }, // Ligurian, Italy → Italian, Italy (no NLS for Ligurian) + { "lmo-IT", "it-IT" }, // Lombard, Italy → Italian, Italy (no NLS for Lombard) + { "prg-PL", "prg-001" }, // Prussian, Poland → Prussian, World (only NLS Prussian) + { "syr-IQ", "syr-SY" }, // Syriac, Iraq → Syriac, Syria (only NLS Syriac) + { "szl-PL", "pl-PL" }, // Silesian, Poland → Polish, Poland (no NLS for Silesian) + { "tok-001", "en-001" }, // Toki Pona, World → English, World (constructed language) + { "vec-IT", "it-IT" }, // Venetian, Italy → Italian, Italy (no NLS for Venetian) + { "vmw-MZ", "pt-MZ" }, // Makhuwa, Mozambique → Portuguese, Mozambique (official language) + { "xnr-IN", "hi-IN" }, // Kangri, India → Hindi, India (no NLS for Kangri) + { "yi-UA", "yi-001" }, // Yiddish, Ukraine → Yiddish, World (only NLS Yiddish) + { "yue-Hans-CN", "zh-CN" }, // Cantonese, Simplified, China → Chinese Simplified, China + { "yue-Hant-HK", "zh-HK" }, // Cantonese, Traditional, Hong Kong → Chinese Traditional, Hong Kong + { "za-CN", "zh-CN" }, // Zhuang, China → Chinese Simplified, China (no NLS for Zhuang) + }; + + foreach (var (icuName, nlsName) in icuToNls) + { + // Prefer a native NLS surrogate for the ICU name if Windows supports it; + // only fall back to copying the mapped NLS surrogate if it does not. + if (TryWriteNlsSurrogate(icuName)) continue; + + var sourceBin = Path.Combine(SurrogatesPath, $"{nlsName.ToLowerInvariant()}.bin"); + var sourceYml = Path.Combine(SurrogatesPathRaw, $"{nlsName.ToLowerInvariant()}.yml"); + + if (File.Exists(sourceBin)) + { + File.Copy(sourceBin, Path.Combine(SurrogatesPath, $"{icuName.ToLowerInvariant()}.bin"), overwrite: true); + } + + if (File.Exists(sourceYml)) { - var dtSurrogate = new DateTimeFormatInfoSurrogate(cultureInfo.DateTimeFormat); - var nfSurrogate = new NumberFormatInfoSurrogate(cultureInfo.NumberFormat); - var ciSurrogate = new CultureInfoSurrogate(dtSurrogate, nfSurrogate); - - var ms = YamlFormatter.SerializeObject(ciSurrogate, o => - { - o.Settings.NamingConvention = NullNamingConvention.Instance; - o.Settings.ReflectionRules = new MemberReflection(); - o.Settings.IndentSequences = false; - }); - - using var fsRawYaml = new FileStream(Path.Combine(SurrogatesPathRaw, $"{cultureInfo.Name.ToLowerInvariant()}.yml"), FileMode.Create); - fsRawYaml.Write(ms.ToByteArray(o => o.LeaveOpen = true), 0, (int)ms.Length); - fsRawYaml.Flush(); - - using var cms = ms.CompressGZip(); - using var fs = new FileStream(Path.Combine(SurrogatesPath, $"{cultureInfo.Name.ToLowerInvariant()}.bin"), FileMode.Create); - fs.Write(cms.ToByteArray(o => o.LeaveOpen = true), 0, (int)cms.Length); - fs.Flush(); + File.Copy(sourceYml, Path.Combine(SurrogatesPathRaw, $"{icuName.ToLowerInvariant()}.yml"), overwrite: true); } } }