1- using MonoMod . RuntimeDetour ;
1+ using BepInEx ;
2+ using MonoMod . RuntimeDetour ;
23using System ;
34using System . Collections . Generic ;
5+ using System . IO ;
46using ValheimLib . Util . Reflection ;
57
68namespace ValheimLib
79{
10+ /// <summary>
11+ /// Class for adding / replacing localization tokens
12+ /// </summary>
813 public static class Language
914 {
15+ /// <summary>
16+ /// Your token must start with this character.
17+ /// </summary>
1018 public const char TokenFirstChar = '$' ;
1119
12- public static List < TokenValue > AdditionalTokens = new List < TokenValue > ( ) ;
20+ internal static Dictionary < string , Dictionary < string , string > > AdditionalTokens =
21+ new Dictionary < string , Dictionary < string , string > > ( ) ;
1322
14- public struct TokenValue
15- {
16- public string Token ;
17- public string Value ;
18- }
23+ internal static Func < StringReader , List < List < string > > > DoQuoteLineSplit ;
1924
20- public static void Init ( )
25+ internal static void Init ( )
2126 {
22- var _ = new Hook (
27+ _ = new Hook (
2328 typeof ( Localization ) . GetMethod ( nameof ( Localization . SetupLanguage ) , ReflectionHelper . AllBindingFlags ) ,
2429 typeof ( Language ) . GetMethod ( nameof ( AddTokens ) , ReflectionHelper . AllBindingFlags ) ) ;
30+
31+ var doQuoteLineSplitMethodInfo = typeof ( Localization ) . GetMethod ( nameof ( Localization . DoQuoteLineSplit ) , ReflectionHelper . AllBindingFlags ) ;
32+ DoQuoteLineSplit = ( Func < StringReader , List < List < string > > > )
33+ Delegate . CreateDelegate ( typeof ( Func < StringReader , List < List < string > > > ) , null , doQuoteLineSplitMethodInfo ) ;
34+
35+ AddLanguageFilesFromPluginFolder ( ) ;
36+ }
37+
38+ private static Dictionary < string , string > GetLanguageDict ( string language )
39+ {
40+ if ( ! AdditionalTokens . TryGetValue ( language , out var languageDict ) )
41+ {
42+ languageDict = new Dictionary < string , string > ( ) ;
43+ AdditionalTokens . Add ( language , languageDict ) ;
44+ }
45+
46+ return languageDict ;
47+ }
48+
49+ private static void AddLanguageFilesFromPluginFolder ( )
50+ {
51+ var languagePaths = Directory . GetFiles ( Paths . PluginPath , "*.language" , SearchOption . AllDirectories ) ;
52+ foreach ( var path in languagePaths )
53+ {
54+ AddPath ( path ) ;
55+ }
2556 }
2657
27- // Todo : for now the custom tokens are getting to any language
28- public static void AddToken ( string token , string value , bool forceReplace = false )
58+ /// <summary>
59+ /// Add a token and its value to the specified language (default to English)
60+ /// </summary>
61+ /// <param name="token">token / key</param>
62+ /// <param name="value">value that will be printed in the game</param>
63+ /// <param name="language"></param>
64+ /// <param name="forceReplace">replace the token if it already exists</param>
65+ public static void AddToken ( string token , string value , string language = "English" , bool forceReplace = false )
2966 {
3067 if ( token [ 0 ] != TokenFirstChar )
3168 {
32- throw new Exception ( $ "Token first char should be $ ! (token : { token } )") ;
69+ throw new Exception ( $ "Token first char should be { TokenFirstChar } ! (token : { token } )") ;
3370 }
3471
72+ Dictionary < string , string > languageDict ;
73+
3574 if ( ! forceReplace )
3675 {
37- foreach ( var pair in AdditionalTokens )
76+ if ( AdditionalTokens . TryGetValue ( language , out languageDict ) )
3877 {
39- if ( pair . Token == token )
78+ foreach ( var pair in languageDict )
4079 {
41- throw new Exception ( $ "Token named { token } already exist !") ;
80+ if ( pair . Key == token )
81+ {
82+ throw new Exception ( $ "Token named { token } already exist !") ;
83+ }
4284 }
4385 }
4486 }
4587
46- AdditionalTokens . Add ( new TokenValue { Token = token . Substring ( 1 ) , Value = value } ) ;
88+ languageDict = GetLanguageDict ( language ) ;
89+ languageDict . Add ( token . Substring ( 1 ) , value ) ;
90+ }
91+
92+ /// <summary>
93+ /// Add a token and its value to the English language
94+ /// </summary>
95+ /// <param name="token">token / key</param>
96+ /// <param name="value">value that will be printed in the game</param>
97+ /// <param name="forceReplace">replace the token if it already exists</param>
98+ public static void AddToken ( string token , string value , bool forceReplace = false ) =>
99+ AddToken ( token , value , "French" , forceReplace ) ;
100+
101+ /// <summary>
102+ /// Add a file via path
103+ /// </summary>
104+ /// <param name="path">absolute path to file</param>
105+ public static void AddPath ( string path )
106+ {
107+ if ( path == null )
108+ {
109+ throw new NullReferenceException ( $ "param { nameof ( path ) } is null") ;
110+ }
111+
112+ var fileContent = File . ReadAllText ( path ) ;
113+ Add ( fileContent ) ;
114+ Log . LogInfo ( $ "Added language file { Path . GetFileName ( path ) } ") ;
115+ }
116+
117+ /// <summary>
118+ /// Add a language file
119+ /// </summary>
120+ /// <param name="fileContent">Entire file as string</param>
121+ public static void Add ( string fileContent )
122+ {
123+ if ( fileContent == null )
124+ {
125+ throw new NullReferenceException ( $ "param { nameof ( fileContent ) } is null") ;
126+ }
127+
128+ LoadLanguageFile ( fileContent ) ;
129+ }
130+
131+ private static void LoadLanguageFile ( string fileContent )
132+ {
133+ var stringReader = new StringReader ( fileContent ) ;
134+ var languages = stringReader . ReadLine ( ) . Split ( new [ ] { ',' } ) ;
135+
136+ foreach ( List < string > keyAndValues in DoQuoteLineSplit ( stringReader ) )
137+ {
138+ if ( keyAndValues . Count != 0 )
139+ {
140+ var token = keyAndValues [ 0 ] ;
141+ if ( ! token . StartsWith ( "//" ) && token . Length != 0 )
142+ {
143+ for ( var i = 0 ; i < languages . Length ; i ++ )
144+ {
145+ var language = languages [ i ] ;
146+
147+ string tokenValue = keyAndValues [ i ] ;
148+ if ( string . IsNullOrEmpty ( tokenValue ) || tokenValue [ 0 ] == '\r ' )
149+ {
150+ tokenValue = keyAndValues [ 1 ] ;
151+ }
152+
153+ var languageDict = GetLanguageDict ( language ) ;
154+ languageDict . Add ( token , tokenValue ) ;
155+ }
156+ }
157+ }
158+ }
47159 }
48160
49161 private static bool AddTokens ( Func < Localization , string , bool > orig , Localization self , string language )
@@ -52,9 +164,12 @@ private static bool AddTokens(Func<Localization, string, bool> orig, Localizatio
52164
53165 if ( res )
54166 {
55- foreach ( var pair in AdditionalTokens )
167+ if ( AdditionalTokens . TryGetValue ( language , out var tokens ) )
56168 {
57- self . AddWord ( pair . Token , pair . Value ) ;
169+ foreach ( var pair in tokens )
170+ {
171+ self . AddWord ( pair . Key , pair . Value ) ;
172+ }
58173 }
59174 }
60175
0 commit comments