11using System ;
22using System . Collections . Generic ;
33using System . Globalization ;
4- using System . IO ;
54using System . Linq ;
65using System . Resources ;
76using System . Runtime . CompilerServices ;
87
98[ assembly: InternalsVisibleTo ( "LocalizationTests" ) ]
109namespace CenturyLocalization
1110{
12- public class Localization
13- {
14- public CultureInfo CurrentLanguage { get ; set ; }
11+ public class Localization
12+ {
13+ public CultureInfo CurrentLanguage { get ; set ; }
1514
16- private readonly ResourceManager _resourceManager ;
15+ private readonly ResourceManager _resourceManager ;
1716 private readonly ResourceManager _countryNamesResourceManager ;
18- private readonly ResourceManager _actionsResourceManager ;
17+ private readonly ResourceManager _actionsResourceManager ;
1918
2019 public Localization ( )
21- {
22- _resourceManager = Texts . ResourceManager ;
20+ {
21+ _resourceManager = Texts . ResourceManager ;
2322 _countryNamesResourceManager = CountryNames . CountryNames . ResourceManager ;
24- _actionsResourceManager = Actions . Actions . ResourceManager ;
23+ _actionsResourceManager = Actions . Actions . ResourceManager ;
2524 CurrentLanguage = CultureInfo . CurrentUICulture ;
26- }
25+ }
2726
28- public string GetText ( string name )
29- {
30- return GetText ( name , CurrentLanguage ) ;
27+ public string GetText ( string name )
28+ {
29+ return GetText ( name , CurrentLanguage ) ;
3130 }
3231
3332 public string GetText ( string name , CultureInfo cultureInfo )
@@ -42,71 +41,52 @@ public string GetText(string name, CultureInfo cultureInfo)
4241
4342 public IEnumerable < CultureInfo > GetAvailableCultures ( string neutralCultureName = "en" )
4443 {
45- var assembly = typeof ( Localization ) . Assembly ;
46- string baseDir = Path . GetDirectoryName ( assembly . Location ) ! ;
4744
48- var cultures = new List < CultureInfo > ( ) ;
49- var seen = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
50-
51- foreach ( var dir in Directory . GetDirectories ( baseDir ) )
45+ var managers = new [ ]
5246 {
53- string folderName = Path . GetFileName ( dir ) ;
47+ _resourceManager ,
48+ _countryNamesResourceManager ,
49+ _actionsResourceManager
50+ } ;
5451
55- if ( ! LooksLikeCulture ( folderName ) )
56- continue ;
52+ // Get all framework-known cultures and probe which ones actually have resources.
53+ // We exclude invariant at this stage and add the neutral explicitly later.
54+ var all = CultureInfo . GetCultures ( CultureTypes . AllCultures )
55+ . Where ( c => c != CultureInfo . InvariantCulture ) ;
5756
58- CultureInfo ? culture = TryCreateCulture ( folderName ) ;
59- if ( culture is null ) continue ;
57+ var supported = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
6058
61- if ( HasResourcesForCulture ( _resourceManager , culture ) ||
62- HasResourcesForCulture ( _countryNamesResourceManager , culture ) ||
63- HasResourcesForCulture ( _actionsResourceManager , culture ) )
59+ foreach ( var culture in all )
60+ {
61+ foreach ( var rm in managers )
6462 {
65- if ( seen . Add ( culture . Name ) )
66- cultures . Add ( culture ) ;
63+ try
64+ {
65+ // tryParents: false ensures we only count cultures with actual satellite resources,
66+ // not those satisfied by fallback.
67+ var set = rm . GetResourceSet ( culture , createIfNotExists : true , tryParents : false ) ;
68+ if ( set != null )
69+ {
70+ supported . Add ( culture . Name ) ;
71+ break ; // This culture is supported by at least one RM
72+ }
73+ }
74+ catch
75+ {
76+ // Ignore probing errors; continue checking other cultures.
77+ }
6778 }
6879 }
6980
70- // Replace invariant with your neutral language (en)
81+ // Ensure your neutral language is always present instead of invariant
7182 var neutral = new CultureInfo ( neutralCultureName ) ;
72- if ( seen . Add ( neutral . Name ) )
73- cultures . Add ( neutral ) ;
83+ supported . Add ( neutral . Name ) ;
7484
75- // Sort for stable output (optional)
76- cultures = cultures
77- . DistinctBy ( c => c . Name )
78- . OrderBy ( c => c . Name , StringComparer . OrdinalIgnoreCase )
85+ // Return as CultureInfo list; order by NativeName for nicer UX
86+ return supported
87+ . Select ( name => new CultureInfo ( name ) )
88+ . OrderBy ( c => c . NativeName , StringComparer . CurrentCultureIgnoreCase )
7989 . ToList ( ) ;
80-
81- return cultures ;
8290 }
83-
84- private static bool LooksLikeCulture ( string name )
85- {
86- // Fast path to avoid exceptions; allows "xx" or "xx-YY"
87- return name . Length is 2 or 5 && ( char . IsLetter ( name [ 0 ] ) && char . IsLetter ( name [ 1 ] ) ) ;
88- }
89-
90- private static CultureInfo ? TryCreateCulture ( string name )
91- {
92- try { return new CultureInfo ( name ) ; }
93- catch ( CultureNotFoundException ) { return null ; }
94- }
95-
96- private static bool HasResourcesForCulture ( ResourceManager manager , CultureInfo culture )
97- {
98- try
99- {
100- // 'tryParents: false' ensures we only count cultures that have actual satellite resources
101- var rmSet = manager . GetResourceSet ( culture , createIfNotExists : true , tryParents : false ) ;
102- return rmSet != null ;
103- }
104- catch
105- {
106- return false ;
107- }
108- }
109-
110-
11191 }
11292}
0 commit comments