-
Notifications
You must be signed in to change notification settings - Fork 7
/
FluentProvider.cs
126 lines (107 loc) · 3.75 KB
/
FluentProvider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using StardewModdingAPI;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Shockah.ProjectFluent
{
internal interface IFluentProvider
{
IFluent<string> GetFluent(IGameLocale locale, IManifest mod, string? file = null);
}
internal class FluentProvider : IFluentProvider, IDisposable
{
private IMonitor Monitor { get; init; }
private IFallbackFluentProvider FallbackFluentProvider { get; init; }
private IModFluentPathProvider ModFluentPathProvider { get; init; }
private IContextfulFluentFunctionProvider ContextfulFluentFunctionProvider { get; init; }
private IList<WeakReference<Fluent>> Fluents { get; set; } = new List<WeakReference<Fluent>>();
public FluentProvider(
IMonitor monitor,
IFallbackFluentProvider fallbackFluentProvider,
IModFluentPathProvider modFluentPathProvider,
IContextfulFluentFunctionProvider contextfulFluentFunctionProvider
)
{
this.Monitor = monitor;
this.FallbackFluentProvider = fallbackFluentProvider;
this.ModFluentPathProvider = modFluentPathProvider;
this.ContextfulFluentFunctionProvider = contextfulFluentFunctionProvider;
ModFluentPathProvider.CandidatesChanged += OnCandidatesChanged;
}
public void Dispose()
{
ModFluentPathProvider.CandidatesChanged -= OnCandidatesChanged;
}
private void OnCandidatesChanged(IModFluentPathProvider provider)
{
foreach (var reference in Fluents)
{
if (!reference.TryGetTarget(out var cached))
continue;
cached.MarkDirty();
}
}
public IFluent<string> GetFluent(IGameLocale locale, IManifest mod, string? file = null)
{
var toRemove = Fluents.Where(r => !r.TryGetTarget(out _)).ToList();
foreach (var reference in toRemove)
Fluents.Remove(reference);
foreach (var reference in Fluents)
{
if (!reference.TryGetTarget(out var cached))
continue;
if (cached.Locale.LocaleCode == locale.LocaleCode && cached.Mod.UniqueID == mod.UniqueID && cached.File == file)
return cached;
}
var fluent = new Fluent(locale, mod, file, FallbackFluentProvider.GetFallbackFluent(mod), Monitor, ModFluentPathProvider, ContextfulFluentFunctionProvider);
Fluents.Add(new WeakReference<Fluent>(fluent));
return fluent;
}
private class Fluent : IFluent<string>
{
internal IGameLocale Locale { get; private init; }
internal IManifest Mod { get; private init; }
internal string? File { get; private init; }
private IFluent<string> Fallback { get; init; }
private IMonitor Monitor { get; init; }
private IModFluentPathProvider ModFluentPathProvider { get; init; }
private IContextfulFluentFunctionProvider ContextfulFluentFunctionProvider { get; init; }
private IFluent<string>? CachedFluent { get; set; }
private IFluent<string> CurrentFluent
{
get
{
CachedFluent ??= new FileResolvingFluent(
ContextfulFluentFunctionProvider.GetFluentFunctionsForMod(Mod),
Monitor,
Locale, ModFluentPathProvider.GetFilePathCandidates(Locale, Mod, File), Fallback
);
return CachedFluent;
}
}
public Fluent(
IGameLocale locale, IManifest mod, string? file, IFluent<string> fallback,
IMonitor monitor,
IModFluentPathProvider modFluentPathProvider,
IContextfulFluentFunctionProvider contextfulFluentFunctionProvider
)
{
this.Locale = locale;
this.Mod = mod;
this.File = file;
this.Fallback = fallback;
this.Monitor = monitor;
this.ModFluentPathProvider = modFluentPathProvider;
this.ContextfulFluentFunctionProvider = contextfulFluentFunctionProvider;
}
internal void MarkDirty()
{
CachedFluent = null;
}
public bool ContainsKey(string key)
=> CurrentFluent.ContainsKey(key);
public string Get(string key, object? tokens)
=> CurrentFluent.Get(key, tokens);
}
}
}