@@ -23,6 +23,12 @@ public class LocalizationValidationTests
2323 "Title" ,
2424 } ;
2525
26+ private static readonly IReadOnlyDictionary < string , HashSet < string > > SupportedLocalizablePropertiesByElement =
27+ new Dictionary < string , HashSet < string > > ( StringComparer . Ordinal )
28+ {
29+ [ "TextBlock" ] = new ( StringComparer . Ordinal ) { "Text" } ,
30+ } ;
31+
2632 private static readonly HashSet < string > InvariantOrDeferredResourceKeys = new ( StringComparer . Ordinal )
2733 {
2834 "AboutPage_TextBlock_19.Text" ,
@@ -366,6 +372,57 @@ public void XamlControlsWithXUid_HaveMatchingEnUsResources()
366372 string . Join ( "; " , missing . Take ( 50 ) ) ) ;
367373 }
368374
375+ [ Fact ]
376+ public void XamlControlsWithXUid_DoNotUseUnsupportedLocalizationProperties ( )
377+ {
378+ var winUiRoot = Path . Combine ( GetRepositoryRoot ( ) , "src" , "OpenClaw.Tray.WinUI" ) ;
379+ var resourceKeys = LoadResw ( Path . Combine ( GetStringsDirectory ( ) , "en-us" , "Resources.resw" ) )
380+ . Keys
381+ . ToList ( ) ;
382+ var invalid = new List < string > ( ) ;
383+
384+ foreach ( var xamlPath in Directory . EnumerateFiles ( winUiRoot , "*.xaml" , SearchOption . AllDirectories )
385+ . Where ( IsSourceXaml )
386+ . OrderBy ( p => p , StringComparer . OrdinalIgnoreCase ) )
387+ {
388+ var relativePath = Path . GetRelativePath ( GetRepositoryRoot ( ) , xamlPath ) ;
389+ var doc = XDocument . Load ( xamlPath , LoadOptions . SetLineInfo ) ;
390+
391+ foreach ( var element in doc . Descendants ( ) )
392+ {
393+ var elementName = element . Name . LocalName ;
394+ var uid = element . Attribute ( XamlNamespace + "Uid" ) ? . Value ;
395+ if ( string . IsNullOrWhiteSpace ( uid ) ||
396+ ! SupportedLocalizablePropertiesByElement . TryGetValue ( elementName , out var supportedProperties ) )
397+ {
398+ continue ;
399+ }
400+
401+ var resourcePrefix = $ "{ uid } .";
402+ foreach ( var key in resourceKeys . Where ( k => k . StartsWith ( resourcePrefix , StringComparison . Ordinal ) ) )
403+ {
404+ var propertyName = key [ resourcePrefix . Length ..] ;
405+ if ( ! LocalizableXamlAttributes . Contains ( propertyName ) ||
406+ supportedProperties . Contains ( propertyName ) )
407+ {
408+ continue ;
409+ }
410+
411+ var line = element is IXmlLineInfo lineInfo && lineInfo . HasLineInfo ( )
412+ ? lineInfo . LineNumber
413+ : 0 ;
414+ invalid . Add (
415+ $ "{ relativePath } :{ line } { elementName } x:Uid=\" { uid } \" cannot use resource '{ key } '. " +
416+ $ "Supported localizable properties: { string . Join ( ", " , supportedProperties . OrderBy ( p => p , StringComparer . Ordinal ) ) } ") ;
417+ }
418+ }
419+ }
420+
421+ Assert . True ( invalid . Count == 0 ,
422+ "XAML localization resources must target properties that exist on the x:Uid element. Invalid: " +
423+ string . Join ( "; " , invalid . Take ( 50 ) ) ) ;
424+ }
425+
369426 private static bool IsSourceXaml ( string path )
370427 {
371428 var relative = Path . GetRelativePath ( GetRepositoryRoot ( ) , path ) ;
0 commit comments