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);
}
}
}