Skip to content
This repository was archived by the owner on Apr 7, 2021. It is now read-only.

Commit b13b1ca

Browse files
committed
Language supports loading from files and multi languages
1 parent 6690d4f commit b13b1ca

1 file changed

Lines changed: 133 additions & 18 deletions

File tree

ValheimLib/Language.cs

Lines changed: 133 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,161 @@
1-
using MonoMod.RuntimeDetour;
1+
using BepInEx;
2+
using MonoMod.RuntimeDetour;
23
using System;
34
using System.Collections.Generic;
5+
using System.IO;
46
using ValheimLib.Util.Reflection;
57

68
namespace 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

Comments
 (0)