@@ -192,22 +192,166 @@ private static ImmutableArray<LocalizableString> ParseXamlFile(AdditionalText fi
192192
193193 if ( key != null )
194194 {
195- localizableStrings . Add ( ParseLocalizableString ( key , value , comment ) ) ;
195+ var formatParams = GetParameters ( value ) ;
196+ var ( summary , updatedFormatParams ) = ParseCommentAndUpdateParameters ( comment , formatParams ) ;
197+ localizableStrings . Add ( new LocalizableString ( key , value , summary , updatedFormatParams ) ) ;
196198 }
197199 }
198200
199201 return localizableStrings . ToImmutableArray ( ) ;
200202 }
201203
202- private static LocalizableString ParseLocalizableString ( string key , string value , XComment comment )
204+ /// <summary>
205+ /// Analyzes the format string and returns a list of its parameters.
206+ /// </summary>
207+ /// <param name="format"></param>
208+ /// <returns></returns>
209+ private static List < LocalizableStringParam > GetParameters ( string format )
203210 {
204- var ( summary , parameters ) = ParseComment ( comment ) ;
205- return new LocalizableString ( key , value , summary , parameters ) ;
211+ var parameters = new Dictionary < int , string > ( ) ;
212+ int maxIndex = - 1 ;
213+ int i = 0 ;
214+ int len = format . Length ;
215+
216+ while ( i < len )
217+ {
218+ if ( format [ i ] == '{' )
219+ {
220+ if ( i + 1 < len && format [ i + 1 ] == '{' )
221+ {
222+ // Escaped '{', skip both
223+ i += 2 ;
224+ continue ;
225+ }
226+ else
227+ {
228+ // Start of a format item, parse index and format
229+ i ++ ; // Move past '{'
230+ int index = 0 ;
231+ bool hasIndex = false ;
232+
233+ // Parse index
234+ while ( i < len && char . IsDigit ( format [ i ] ) )
235+ {
236+ hasIndex = true ;
237+ index = index * 10 + ( format [ i ] - '0' ) ;
238+ i ++ ;
239+ }
240+
241+ if ( ! hasIndex )
242+ {
243+ // Skip invalid format item
244+ while ( i < len && format [ i ] != '}' )
245+ {
246+ i ++ ;
247+ }
248+ if ( i < len )
249+ {
250+ i ++ ; // Move past '}'
251+ }
252+ continue ;
253+ }
254+
255+ // Check for alignment (comma followed by optional sign and digits)
256+ if ( i < len && format [ i ] == ',' )
257+ {
258+ i ++ ; // Skip comma and optional sign
259+ if ( i < len && ( format [ i ] == '+' || format [ i ] == '-' ) )
260+ {
261+ i ++ ;
262+ }
263+ // Skip digits
264+ while ( i < len && char . IsDigit ( format [ i ] ) )
265+ {
266+ i ++ ;
267+ }
268+ }
269+
270+ string formatPart = null ;
271+
272+ // Check for format (after colon)
273+ if ( i < len && format [ i ] == ':' )
274+ {
275+ i ++ ; // Move past ':'
276+ int start = i ;
277+ while ( i < len && format [ i ] != '}' )
278+ {
279+ i ++ ;
280+ }
281+ formatPart = i < len ? format . Substring ( start , i - start ) : format . Substring ( start ) ;
282+ if ( i < len )
283+ {
284+ i ++ ; // Move past '}'
285+ }
286+ }
287+ else if ( i < len && format [ i ] == '}' )
288+ {
289+ // No format part
290+ i ++ ; // Move past '}'
291+ }
292+ else
293+ {
294+ // Invalid characters after index, skip to '}'
295+ while ( i < len && format [ i ] != '}' )
296+ {
297+ i ++ ;
298+ }
299+ if ( i < len )
300+ {
301+ i ++ ; // Move past '}'
302+ }
303+ }
304+
305+ parameters [ index ] = formatPart ;
306+ if ( index > maxIndex )
307+ {
308+ maxIndex = index ;
309+ }
310+ }
311+ }
312+ else if ( format [ i ] == '}' )
313+ {
314+ // Handle possible escaped '}}'
315+ if ( i + 1 < len && format [ i + 1 ] == '}' )
316+ {
317+ i += 2 ; // Skip escaped '}}'
318+ }
319+ else
320+ {
321+ i ++ ; // Move past '}'
322+ }
323+ }
324+ else
325+ {
326+ i ++ ;
327+ }
328+ }
329+
330+ // Generate the result list from 0 to maxIndex
331+ var result = new List < LocalizableStringParam > ( ) ;
332+ if ( maxIndex == - 1 )
333+ {
334+ return result ;
335+ }
336+
337+ for ( int idx = 0 ; idx <= maxIndex ; idx ++ )
338+ {
339+ var formatValue = parameters . TryGetValue ( idx , out var value ) ? value : null ;
340+ result . Add ( new LocalizableStringParam { Index = idx , Format = formatValue , Name = $ "arg{ idx } ", Type = "object?" } ) ;
341+ }
342+
343+ return result ;
206344 }
207345
208- private static ( string Summary , ImmutableArray < LocalizableStringParam > Parameters ) ParseComment ( XComment comment )
346+ /// <summary>
347+ /// Parses the comment and updates the format parameter names and types.
348+ /// </summary>
349+ /// <param name="comment"></param>
350+ /// <param name="parameters"></param>
351+ /// <returns></returns>
352+ private static ( string Summary , ImmutableArray < LocalizableStringParam > Parameters ) ParseCommentAndUpdateParameters ( XComment comment , List < LocalizableStringParam > parameters )
209353 {
210- if ( comment == null || comment . Value == null )
354+ if ( comment == null || comment . Value == null || parameters . Count == 0 )
211355 {
212356 return ( null , _emptyLocalizableStringParams ) ;
213357 }
@@ -216,13 +360,26 @@ private static (string Summary, ImmutableArray<LocalizableStringParam> Parameter
216360 {
217361 var doc = XDocument . Parse ( $ "<root>{ comment . Value } </root>") ;
218362 var summary = doc . Descendants ( "summary" ) . FirstOrDefault ( ) ? . Value . Trim ( ) ;
219- var parameters = doc . Descendants ( "param" )
220- . Select ( p => new LocalizableStringParam (
221- int . Parse ( p . Attribute ( "index" ) . Value ) ,
222- p . Attribute ( "name" ) . Value ,
223- p . Attribute ( "type" ) . Value ) )
224- . ToImmutableArray ( ) ;
225- return ( summary , parameters ) ;
363+
364+ // Update parameter names and types of the format string
365+ foreach ( var p in doc . Descendants ( "param" ) )
366+ {
367+ var index = int . TryParse ( p . Attribute ( "index" ) . Value , out var intValue ) ? intValue : - 1 ;
368+ var name = p . Attribute ( "name" ) . Value ;
369+ var type = p . Attribute ( "type" ) . Value ;
370+ if ( index >= 0 && index < parameters . Count )
371+ {
372+ if ( ! string . IsNullOrEmpty ( name ) )
373+ {
374+ parameters [ index ] . Name = name ;
375+ }
376+ if ( ! string . IsNullOrEmpty ( type ) )
377+ {
378+ parameters [ index ] . Type = type ;
379+ }
380+ }
381+ }
382+ return ( summary , parameters . ToImmutableArray ( ) ) ;
226383 }
227384 catch
228385 {
@@ -521,25 +678,32 @@ private static void GenerateLocalizationMethod(
521678 string tabString )
522679 {
523680 sb . Append ( $ "{ tabString } public static string { ls . Key } (") ;
524- var parameters = BuildParameters ( ls ) ;
681+
682+ // Get parameter string
683+ var parameters = ls . Params . ToList ( ) ;
525684 sb . Append ( string . Join ( ", " , parameters . Select ( p => $ "{ p . Type } { p . Name } ") ) ) ;
526685 sb . Append ( ") => " ) ;
527-
528686 var formatArgs = parameters . Count > 0
529687 ? $ ", { string . Join ( ", " , parameters . Select ( p => p . Name ) ) } "
530688 : string . Empty ;
531689
532690 if ( isCoreAssembly )
533691 {
692+ var getTranslation = "InternationalizationManager.Instance.GetTranslation" ;
534693 sb . AppendLine ( parameters . Count > 0
535- ? $ "string.Format(InternationalizationManager.Instance.GetTranslation(\" { ls . Key } \" ){ formatArgs } );"
536- : $ "InternationalizationManager.Instance.GetTranslation(\" { ls . Key } \" );") ;
694+ ? ! ls . Format ?
695+ $ "string.Format({ getTranslation } (\" { ls . Key } \" ){ formatArgs } );"
696+ : $ "string.Format(System.Globalization.CultureInfo.CurrentCulture, { getTranslation } (\" { ls . Key } \" ){ formatArgs } );"
697+ : $ "{ getTranslation } (\" { ls . Key } \" );") ;
537698 }
538699 else if ( pluginInfo ? . IsValid == true )
539700 {
701+ var getTranslation = $ "{ pluginInfo . ContextAccessor } .API.GetTranslation";
540702 sb . AppendLine ( parameters . Count > 0
541- ? $ "string.Format({ pluginInfo . ContextAccessor } .API.GetTranslation(\" { ls . Key } \" ){ formatArgs } );"
542- : $ "{ pluginInfo . ContextAccessor } .API.GetTranslation(\" { ls . Key } \" );") ;
703+ ? ! ls . Format ?
704+ $ "string.Format({ getTranslation } (\" { ls . Key } \" ){ formatArgs } );"
705+ : $ "string.Format(System.Globalization.CultureInfo.CurrentCulture, { getTranslation } (\" { ls . Key } \" ){ formatArgs } );"
706+ : $ "{ getTranslation } (\" { ls . Key } \" );") ;
543707 }
544708 else
545709 {
@@ -549,24 +713,6 @@ private static void GenerateLocalizationMethod(
549713 sb . AppendLine ( ) ;
550714 }
551715
552- private static List < MethodParameter > BuildParameters ( LocalizableString ls )
553- {
554- var parameters = new List < MethodParameter > ( ) ;
555- for ( var i = 0 ; i < 10 ; i ++ )
556- {
557- if ( ! ls . Value . Contains ( $ "{{{i}}}") )
558- {
559- continue ;
560- }
561-
562- var param = ls . Params . FirstOrDefault ( p => p . Index == i ) ;
563- parameters . Add ( param is null
564- ? new MethodParameter ( $ "arg{ i } ", "object?" )
565- : new MethodParameter ( param . Name , param . Type ) ) ;
566- }
567- return parameters ;
568- }
569-
570716 private static string Spacing ( int n )
571717 {
572718 Span < char > spaces = stackalloc char [ n * 4 ] ;
@@ -585,30 +731,12 @@ private static string Spacing(int n)
585731
586732 #region Classes
587733
588- public class MethodParameter
589- {
590- public string Name { get ; }
591- public string Type { get ; }
592-
593- public MethodParameter ( string name , string type )
594- {
595- Name = name ;
596- Type = type ;
597- }
598- }
599-
600734 public class LocalizableStringParam
601735 {
602- public int Index { get ; }
603- public string Name { get ; }
604- public string Type { get ; }
605-
606- public LocalizableStringParam ( int index , string name , string type )
607- {
608- Index = index ;
609- Name = name ;
610- Type = type ;
611- }
736+ public int Index { get ; set ; }
737+ public string Format { get ; set ; }
738+ public string Name { get ; set ; }
739+ public string Type { get ; set ; }
612740 }
613741
614742 public class LocalizableString
@@ -617,6 +745,8 @@ public class LocalizableString
617745 public string Value { get ; }
618746 public string Summary { get ; }
619747 public IEnumerable < LocalizableStringParam > Params { get ; }
748+
749+ public bool Format => Params . Any ( p => ! string . IsNullOrEmpty ( p . Format ) ) ;
620750
621751 public LocalizableString ( string key , string value , string summary , IEnumerable < LocalizableStringParam > @params )
622752 {
0 commit comments