@@ -13,40 +14,40 @@
General
-
-
-
-
-
+
+
+
+
+
Business
-
-
-
-
-
-
+
+
+
+
+
+
Learning
-
+
Software Engineering
-
+
@if (PreviewFeatures.PRE_RAG_2024.IsEnabled(this.SettingsManager))
{
-
+
}
diff --git a/app/MindWork AI Studio/Pages/Assistants.razor.cs b/app/MindWork AI Studio/Pages/Assistants.razor.cs
index ef2af6db..e2c2de49 100644
--- a/app/MindWork AI Studio/Pages/Assistants.razor.cs
+++ b/app/MindWork AI Studio/Pages/Assistants.razor.cs
@@ -1,11 +1,5 @@
-using AIStudio.Settings;
-
-using Microsoft.AspNetCore.Components;
+using AIStudio.Components;
namespace AIStudio.Pages;
-public partial class Assistants : ComponentBase
-{
- [Inject]
- public SettingsManager SettingsManager { get; set; } = null!;
-}
\ No newline at end of file
+public partial class Assistants : MSGComponentBase;
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Pages/Chat.razor b/app/MindWork AI Studio/Pages/Chat.razor
index 418a17cc..5586f262 100644
--- a/app/MindWork AI Studio/Pages/Chat.razor
+++ b/app/MindWork AI Studio/Pages/Chat.razor
@@ -25,7 +25,7 @@
// Case: Sidebar can be toggled and is currently visible
-
+
@@ -88,7 +88,7 @@
- Your workspaces
+ @T("Your workspaces")
diff --git a/app/MindWork AI Studio/Pages/Chat.razor.cs b/app/MindWork AI Studio/Pages/Chat.razor.cs
index f3c5c8b5..56a5535e 100644
--- a/app/MindWork AI Studio/Pages/Chat.razor.cs
+++ b/app/MindWork AI Studio/Pages/Chat.razor.cs
@@ -82,8 +82,6 @@ public partial class Chat : MSGComponentBase
#region Overrides of MSGComponentBase
- public override string ComponentName => nameof(Chat);
-
protected override Task ProcessIncomingMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
{
switch (triggeredEvent)
diff --git a/app/MindWork AI Studio/Pages/Home.razor b/app/MindWork AI Studio/Pages/Home.razor
index 0b035995..d2bfdb93 100644
--- a/app/MindWork AI Studio/Pages/Home.razor
+++ b/app/MindWork AI Studio/Pages/Home.razor
@@ -12,31 +12,29 @@
- Welcome to MindWork AI Studio!
+ @T("Welcome to MindWork AI Studio!")
- Thank you for considering MindWork AI Studio for your AI needs. This app is designed to help you harness
- the power of Large Language Models (LLMs). Please note that this app doesn't come with an integrated
- LLM. Instead, you will need to bring an API key from a suitable provider.
+ @T("Thank you for considering MindWork AI Studio for your AI needs. This app is designed to help you harness the power of Large Language Models (LLMs). Please note that this app doesn't come with an integrated LLM. Instead, you will need to bring an API key from a suitable provider.")
- Here's what makes MindWork AI Studio stand out:
+ @T("Here's what makes MindWork AI Studio stand out:")
-
+
- We hope you enjoy using MindWork AI Studio to bring your AI projects to life!
+ @T("We hope you enjoy using MindWork AI Studio to bring your AI projects to life!")
-
+
-
+
-
+
diff --git a/app/MindWork AI Studio/Pages/Home.razor.cs b/app/MindWork AI Studio/Pages/Home.razor.cs
index 6a5dfff0..85cae0e9 100644
--- a/app/MindWork AI Studio/Pages/Home.razor.cs
+++ b/app/MindWork AI Studio/Pages/Home.razor.cs
@@ -13,41 +13,38 @@ public partial class Home : MSGComponentBase
private string LastChangeContent { get; set; } = string.Empty;
+ private TextItem[] itemsAdvantages = [];
+
#region Overrides of ComponentBase
protected override async Task OnInitializedAsync()
{
await this.ReadLastChangeAsync();
await base.OnInitializedAsync();
+
+ this.itemsAdvantages = [
+ new(T("Free of charge"), T("The app is free to use, both for personal and commercial purposes.")),
+ new(T("Independence"), T("You are not tied to any single provider. Instead, you might choose the provider that best suits your needs. Right now, we support OpenAI (GPT4o, o1, etc.), Mistral, Anthropic (Claude), Google Gemini, xAI (Grok), DeepSeek, Alibaba Cloud (Qwen), Hugging Face, and self-hosted models using llama.cpp, ollama, LM Studio, Groq, or Fireworks. For scientists and employees of research institutions, we also support Helmholtz and GWDG AI services. These are available through federated logins like eduGAIN to all 18 Helmholtz Centers, the Max Planck Society, most German, and many international universities.")),
+ new(T("Assistants"), T("You just want to quickly translate a text? AI Studio has so-called assistants for such and other tasks. No prompting is necessary when working with these assistants.")),
+ new(T("Unrestricted usage"), T("Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API.")),
+ new(T("Cost-effective"), T("You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit.")),
+ new(T("Privacy"), T("You can control which providers receive your data using the provider confidence settings. For example, you can set different protection levels for writing emails compared to general chats, etc. Additionally, most providers guarantee that they won't use your data to train new AI systems.")),
+ new(T("Flexibility"), T("Choose the provider and model best suited for your current task.")),
+ new(T("No bloatware"), T("The app requires minimal storage for installation and operates with low memory usage. Additionally, it has a minimal impact on system resources, which is beneficial for battery life.")),
+ ];
+
+ this.StateHasChanged();
}
#endregion
- #region Overrides of MSGComponentBase
-
- public override string ComponentName => nameof(Home);
-
- #endregion
-
private async Task ReadLastChangeAsync()
{
var latest = Changelog.LOGS.MaxBy(n => n.Build);
using var response = await this.HttpClient.GetAsync($"changelog/{latest.Filename}");
this.LastChangeContent = await response.Content.ReadAsStringAsync();
}
-
- private static readonly TextItem[] ITEMS_ADVANTAGES =
- [
- new("Free of charge", "The app is free to use, both for personal and commercial purposes."),
- new("Independence", "You are not tied to any single provider. Instead, you might choose the provider that best suits your needs. Right now, we support OpenAI (GPT4o, o1, etc.), Mistral, Anthropic (Claude), Google Gemini, xAI (Grok), DeepSeek, Alibaba Cloud (Qwen), Hugging Face, and self-hosted models using llama.cpp, ollama, LM Studio, Groq, or Fireworks. For scientists and employees of research institutions, we also support Helmholtz and GWDG AI services. These are available through federated logins like eduGAIN to all 18 Helmholtz Centers, the Max Planck Society, most German, and many international universities."),
- new("Assistants", "You just want to quickly translate a text? AI Studio has so-called assistants for such and other tasks. No prompting is necessary when working with these assistants."),
- new("Unrestricted usage", "Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API."),
- new("Cost-effective", "You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit."),
- new("Privacy", "You can control which providers receive your data using the provider confidence settings. For example, you can set different protection levels for writing emails compared to general chats, etc. Additionally, most providers guarantee that they won't use your data to train new AI systems."),
- new("Flexibility", "Choose the provider and model best suited for your current task."),
- new("No bloatware", "The app requires minimal storage for installation and operates with low memory usage. Additionally, it has a minimal impact on system resources, which is beneficial for battery life."),
- ];
-
+
private const string QUICK_START_GUIDE =
"""
Ready to dive in and get started with MindWork AI Studio? This quick start guide will help you set up everything you need to start using the app.
diff --git a/app/MindWork AI Studio/Pages/Plugins.razor b/app/MindWork AI Studio/Pages/Plugins.razor
index 8306d6d1..0db15706 100644
--- a/app/MindWork AI Studio/Pages/Plugins.razor
+++ b/app/MindWork AI Studio/Pages/Plugins.razor
@@ -4,7 +4,7 @@
- Plugins
+ @T("Plugins")
@@ -18,8 +18,8 @@
- Plugins
- Actions
+ @T("Plugins")
+ @T("Actions")
@@ -27,19 +27,19 @@
{
case GROUP_ENABLED:
- Enabled Plugins
+ @T("Enabled Plugins")
break;
case GROUP_DISABLED:
- Disabled Plugins
+ @T("Disabled Plugins")
break;
case GROUP_INTERNAL:
- Internal Plugins
+ @T("Internal Plugins")
break;
}
@@ -67,7 +67,7 @@
@if (!context.IsInternal)
{
var isEnabled = this.SettingsManager.IsPluginEnabled(context);
-
+
}
diff --git a/app/MindWork AI Studio/Pages/Plugins.razor.cs b/app/MindWork AI Studio/Pages/Plugins.razor.cs
index 88c90433..4eb6078c 100644
--- a/app/MindWork AI Studio/Pages/Plugins.razor.cs
+++ b/app/MindWork AI Studio/Pages/Plugins.razor.cs
@@ -1,6 +1,8 @@
using AIStudio.Components;
using AIStudio.Tools.PluginSystem;
+using Microsoft.AspNetCore.Components;
+
namespace AIStudio.Pages;
public partial class Plugins : MSGComponentBase
@@ -15,8 +17,7 @@ public partial class Plugins : MSGComponentBase
protected override async Task OnInitializedAsync()
{
- this.MessageBus.RegisterComponent(this);
- this.MessageBus.ApplyFilters(this, [], [ Event.PLUGINS_RELOADED ]);
+ this.ApplyFilters([], [ Event.PLUGINS_RELOADED ]);
this.groupConfig = new TableGroupDefinition
{
@@ -38,12 +39,6 @@ public partial class Plugins : MSGComponentBase
#endregion
- #region Overrides of MSGComponentBase
-
- public override string ComponentName => nameof(Plugins);
-
- #endregion
-
private async Task PluginActivationStateChanged(IPluginMetadata pluginMeta)
{
if (this.SettingsManager.IsPluginEnabled(pluginMeta))
@@ -54,4 +49,18 @@ public partial class Plugins : MSGComponentBase
await this.SettingsManager.StoreSettings();
await this.MessageBus.SendMessage(this, Event.CONFIGURATION_CHANGED);
}
+
+ #region Overrides of MSGComponentBase
+
+ protected override async Task ProcessIncomingMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
+ {
+ switch (triggeredEvent)
+ {
+ case Event.PLUGINS_RELOADED:
+ await this.InvokeAsync(this.StateHasChanged);
+ break;
+ }
+ }
+
+ #endregion
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Pages/Settings.razor b/app/MindWork AI Studio/Pages/Settings.razor
index c048a542..9cc28223 100644
--- a/app/MindWork AI Studio/Pages/Settings.razor
+++ b/app/MindWork AI Studio/Pages/Settings.razor
@@ -1,9 +1,10 @@
-@attribute [Route(Routes.SETTINGS)]
@using AIStudio.Components.Settings
@using AIStudio.Settings.DataModel
+@attribute [Route(Routes.SETTINGS)]
+@inherits MSGComponentBase
-
Settings
+
@T("Settings")
diff --git a/app/MindWork AI Studio/Pages/Settings.razor.cs b/app/MindWork AI Studio/Pages/Settings.razor.cs
index 57c34c5a..89c7338b 100644
--- a/app/MindWork AI Studio/Pages/Settings.razor.cs
+++ b/app/MindWork AI Studio/Pages/Settings.razor.cs
@@ -1,17 +1,12 @@
+using AIStudio.Components;
using AIStudio.Settings;
using Microsoft.AspNetCore.Components;
namespace AIStudio.Pages;
-public partial class Settings : ComponentBase, IMessageBusReceiver, IDisposable
+public partial class Settings : MSGComponentBase
{
- [Inject]
- private SettingsManager SettingsManager { get; init; } = null!;
-
- [Inject]
- private MessageBus MessageBus { get; init; } = null!;
-
private List> availableLLMProviders = new();
private List> availableEmbeddingProviders = new();
@@ -19,20 +14,16 @@ public partial class Settings : ComponentBase, IMessageBusReceiver, IDisposable
protected override async Task OnInitializedAsync()
{
- // Register this component with the message bus:
- this.MessageBus.RegisterComponent(this);
- this.MessageBus.ApplyFilters(this, [], [ Event.CONFIGURATION_CHANGED ]);
+ this.ApplyFilters([], [ Event.CONFIGURATION_CHANGED ]);
await base.OnInitializedAsync();
}
#endregion
-
- #region Implementation of IMessageBusReceiver
- public string ComponentName => nameof(Settings);
+ #region Overrides of MSGComponentBase
- public Task ProcessMessage(ComponentBase? sendingComponent, Event triggeredEvent, TMsg? data)
+ protected override Task ProcessIncomingMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
{
switch (triggeredEvent)
{
@@ -40,23 +31,9 @@ public partial class Settings : ComponentBase, IMessageBusReceiver, IDisposable
this.StateHasChanged();
break;
}
-
+
return Task.CompletedTask;
}
- public Task ProcessMessageWithResult(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data)
- {
- return Task.FromResult(default);
- }
-
- #endregion
-
- #region Implementation of IDisposable
-
- public void Dispose()
- {
- this.MessageBus.Unregister(this);
- }
-
#endregion
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Pages/Supporters.razor b/app/MindWork AI Studio/Pages/Supporters.razor
index c9350408..a35d4fd1 100644
--- a/app/MindWork AI Studio/Pages/Supporters.razor
+++ b/app/MindWork AI Studio/Pages/Supporters.razor
@@ -1,22 +1,27 @@
@attribute [Route(Routes.SUPPORTERS)]
+@inherits MSGComponentBase
-
Supporters
+
+ @T("Supporters")
+
-
+
- Our Titans
-
- In this section, we highlight the titan supporters of MindWork AI Studio. Titans are prestigious companies that provide significant support to our mission.
+
+ @T("Our Titans")
- For companies, sponsoring MindWork AI Studio is not only a way to support innovation but also a valuable opportunity for public relations and marketing. Your company's name and logo will be featured prominently, showcasing your commitment to using cutting-edge AI tools and enhancing your reputation as an innovative enterprise.
+ @T("In this section, we highlight the titan supporters of MindWork AI Studio. Titans are prestigious companies that provide significant support to our mission.")
+
+
+ @T("For companies, sponsoring MindWork AI Studio is not only a way to support innovation but also a valuable opportunity for public relations and marketing. Your company's name and logo will be featured prominently, showcasing your commitment to using cutting-edge AI tools and enhancing your reputation as an innovative enterprise.")
- Become our first Titan
+ @T("Become our first Titan")
@@ -25,27 +30,27 @@
- Individual Contributors
+ @T("Individual Contributors")
- Become a contributor
+ @T("Become a contributor")
- The first 10 supporters who make a monthly contribution:
+ @T("The first 10 supporters who make a monthly contribution:")
-
-
-
+
+
+
- The first 10 supporters who make a one-time contribution:
+ @T("The first 10 supporters who make a one-time contribution:")
-
+
@@ -54,11 +59,11 @@
- Business Contributors
+ @T("Business Contributors")
- Become a contributor
+ @T("Become a contributor")
@@ -72,14 +77,14 @@
- Code Contributions
+ @T("Code Contributions")
-
-
-
-
+
+
+
+
@@ -88,11 +93,11 @@
- Moderation, Design, Wiki, and Documentation
+ @T("Moderation, Design, Wiki, and Documentation")
-
+
diff --git a/app/MindWork AI Studio/Pages/Supporters.razor.cs b/app/MindWork AI Studio/Pages/Supporters.razor.cs
index 45065ad9..dcd937c9 100644
--- a/app/MindWork AI Studio/Pages/Supporters.razor.cs
+++ b/app/MindWork AI Studio/Pages/Supporters.razor.cs
@@ -1,7 +1,7 @@
+using AIStudio.Components;
+
using Microsoft.AspNetCore.Components;
namespace AIStudio.Pages;
-public partial class Supporters : ComponentBase
-{
-}
\ No newline at end of file
+public partial class Supporters : MSGComponentBase;
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Pages/Writer.razor b/app/MindWork AI Studio/Pages/Writer.razor
index 790e3e07..bead1792 100644
--- a/app/MindWork AI Studio/Pages/Writer.razor
+++ b/app/MindWork AI Studio/Pages/Writer.razor
@@ -3,7 +3,7 @@
- Writer
+ @T("Writer")
@@ -13,7 +13,7 @@
Logger { get; init; } = null!;
@@ -29,7 +29,6 @@ public partial class Writer : MSGComponentBase, IAsyncDisposable
protected override async Task OnInitializedAsync()
{
- this.ApplyFilters([], []);
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
this.typeTimer.Elapsed += async (_, _) => await this.InvokeAsync(this.GetSuggestions);
this.typeTimer.AutoReset = false;
@@ -39,12 +38,6 @@ public partial class Writer : MSGComponentBase, IAsyncDisposable
#endregion
- #region Overrides of MSGComponentBase
-
- public override string ComponentName => nameof(Writer);
-
- #endregion
-
private bool IsProviderSelected => this.providerSettings.UsedLLMProvider != LLMProviders.NONE;
private async Task InputKeyEvent(KeyboardEventArgs keyEvent)
@@ -159,13 +152,4 @@ public partial class Writer : MSGComponentBase, IAsyncDisposable
this.suggestion = string.Join(' ', words.Skip(1));
this.StateHasChanged();
}
-
- #region Implementation of IAsyncDisposable
-
- public ValueTask DisposeAsync()
- {
- return ValueTask.CompletedTask;
- }
-
- #endregion
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Settings/SettingsManager.cs b/app/MindWork AI Studio/Settings/SettingsManager.cs
index 24bd1ded..1f1b543d 100644
--- a/app/MindWork AI Studio/Settings/SettingsManager.cs
+++ b/app/MindWork AI Studio/Settings/SettingsManager.cs
@@ -1,6 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
-using System.Text.Json.Serialization;
using AIStudio.Provider;
using AIStudio.Settings.DataModel;
diff --git a/app/MindWork AI Studio/Tools/IMessageBusReceiver.cs b/app/MindWork AI Studio/Tools/IMessageBusReceiver.cs
index 044e425b..019ce115 100644
--- a/app/MindWork AI Studio/Tools/IMessageBusReceiver.cs
+++ b/app/MindWork AI Studio/Tools/IMessageBusReceiver.cs
@@ -4,8 +4,6 @@ namespace AIStudio.Tools;
public interface IMessageBusReceiver
{
- public string ComponentName { get; }
-
public Task ProcessMessage(ComponentBase? sendingComponent, Event triggeredEvent, T? data);
public Task ProcessMessageWithResult(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data);
diff --git a/app/MindWork AI Studio/Tools/MessageBus.cs b/app/MindWork AI Studio/Tools/MessageBus.cs
index 06a2dfd8..7840ce75 100644
--- a/app/MindWork AI Studio/Tools/MessageBus.cs
+++ b/app/MindWork AI Studio/Tools/MessageBus.cs
@@ -19,9 +19,15 @@ public sealed class MessageBus
{
}
- public void ApplyFilters(IMessageBusReceiver receiver, ComponentBase[] components, Event[] events)
+ ///
+ /// Define for which components and events you want to receive messages.
+ ///
+ /// That's you, the receiver.
+ /// A list of components for which you want to receive messages. Use an empty list to receive messages from all components.
+ /// A list of events for which you want to receive messages.
+ public void ApplyFilters(IMessageBusReceiver receiver, ComponentBase[] filterComponents, Event[] events)
{
- this.componentFilters[receiver] = components;
+ this.componentFilters[receiver] = filterComponents;
this.componentEvents[receiver] = events;
}
diff --git a/app/MindWork AI Studio/Tools/PluginSystem/ILangExtensions.cs b/app/MindWork AI Studio/Tools/PluginSystem/ILangExtensions.cs
new file mode 100644
index 00000000..d1c26856
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/PluginSystem/ILangExtensions.cs
@@ -0,0 +1,29 @@
+using SharedTools;
+
+namespace AIStudio.Tools.PluginSystem;
+
+public static class ILangExtensions
+{
+ private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger();
+
+ public static string GetText(this ILang lang, ILanguagePlugin plugin, string fallbackEN)
+ {
+ var type = lang.GetType();
+ var ns = $"{type.Namespace!}::{type.Name}".ToUpperInvariant().Replace(".", "::");
+ var key = $"root::{ns}::T{fallbackEN.ToFNV32()}";
+
+ if(plugin is NoPluginLanguage)
+ return fallbackEN;
+
+ if(plugin.TryGetText(key, out var text, logWarning: false))
+ {
+ if(string.IsNullOrWhiteSpace(text))
+ return fallbackEN;
+
+ return text;
+ }
+
+ LOGGER.LogDebug($"Missing translation key '{key}' for content '{fallbackEN}'.");
+ return fallbackEN;
+ }
+}
\ No newline at end of file
diff --git a/app/SourceCodeRules/SourceCodeRules/UsageAnalyzers/ThisUsageAnalyzer.cs b/app/SourceCodeRules/SourceCodeRules/UsageAnalyzers/ThisUsageAnalyzer.cs
index f48c374b..1e601a6f 100644
--- a/app/SourceCodeRules/SourceCodeRules/UsageAnalyzers/ThisUsageAnalyzer.cs
+++ b/app/SourceCodeRules/SourceCodeRules/UsageAnalyzers/ThisUsageAnalyzer.cs
@@ -36,7 +36,7 @@ public sealed class ThisUsageAnalyzer : DiagnosticAnalyzer
{
var genericNameSyntax = (GenericNameSyntax)context.Node;
- // Skip if already part of a 'this' expression
+ // Skip if already part of a 'this' expression:
if (IsAccessedThroughThis(genericNameSyntax))
return;
@@ -46,7 +46,11 @@ public sealed class ThisUsageAnalyzer : DiagnosticAnalyzer
if (IsPartOfMemberAccess(genericNameSyntax))
return;
- // Get symbol info for the generic name
+ // Skip if it's the 'T' translation method
+ if (IsTranslationMethod(genericNameSyntax))
+ return;
+
+ // Get symbol info for the generic name:
var symbolInfo = context.SemanticModel.GetSymbolInfo(genericNameSyntax);
var symbol = symbolInfo.Symbol;
@@ -83,15 +87,24 @@ public sealed class ThisUsageAnalyzer : DiagnosticAnalyzer
}
}
+ private static bool IsTranslationMethod(SyntaxNode node)
+ {
+ // Check if this is a method called 'T' (translation method)
+ if (node is IdentifierNameSyntax { Identifier.Text: "T" })
+ return true;
+
+ return false;
+ }
+
private void AnalyzeIdentifier(SyntaxNodeAnalysisContext context)
{
var identifierNameSyntax = (IdentifierNameSyntax)context.Node;
- // Skip if this identifier is part of a generic name - we'll handle that separately
+ // Skip if this identifier is part of a generic name - we'll handle that separately:
if (identifierNameSyntax.Parent is GenericNameSyntax)
return;
- // Skip if already part of a 'this' expression
+ // Skip if already part of a 'this' expression:
if (IsAccessedThroughThis(identifierNameSyntax))
return;
@@ -101,55 +114,59 @@ public sealed class ThisUsageAnalyzer : DiagnosticAnalyzer
if (IsPartOfMemberAccess(identifierNameSyntax))
return;
- // Also skip if it's part of static import statements
+ // Also skip if it's part of static import statements:
if (IsPartOfUsingStaticDirective(identifierNameSyntax))
return;
- // Skip if it's part of a namespace or type name
+ // Skip if it's part of a namespace or type name:
if (IsPartOfNamespaceOrTypeName(identifierNameSyntax))
return;
- // Get symbol info
+ // Skip if it's the 'T' translation method:
+ if (IsTranslationMethod(identifierNameSyntax))
+ return;
+
+ // Get symbol info:
var symbolInfo = context.SemanticModel.GetSymbolInfo(identifierNameSyntax);
var symbol = symbolInfo.Symbol;
if (symbol == null)
return;
- // Skip local variables, parameters, and range variables
+ // Skip local variables, parameters, and range variables:
if (symbol.Kind is SymbolKind.Local or SymbolKind.Parameter or SymbolKind.RangeVariable or SymbolKind.TypeParameter)
return;
- // Skip types and namespaces
+ // Skip types and namespaces:
if (symbol.Kind is SymbolKind.NamedType or SymbolKind.Namespace)
return;
- // Explicitly check if this is a local function
+ // Explicitly check if this is a local function:
if (symbol is IMethodSymbol methodSymbol && IsLocalFunction(methodSymbol))
return;
- // Get the containing type of the current context
+ // Get the containing type of the current context:
var containingSymbol = context.ContainingSymbol;
var currentType = containingSymbol?.ContainingType;
- // If we're in a static context, allow accessing members without this
+ // If we're in a static context, allow accessing members without this:
if (IsInStaticContext(containingSymbol))
return;
- // Now check if the symbol is an instance member of the current class
+ // Now check if the symbol is an instance member of the current class:
if (symbol is IFieldSymbol or IPropertySymbol or IMethodSymbol or IEventSymbol)
{
- // Skip static members
+ // Skip static members:
if (symbol.IsStatic)
return;
- // Skip constants
+ // Skip constants:
if (symbol is IFieldSymbol { IsConst: true })
return;
var containingType = symbol.ContainingType;
- // If the symbol is a member of the current type or a base type, then require this
+ // If the symbol is a member of the current type or a base type, then require this:
if (currentType != null && (SymbolEqualityComparer.Default.Equals(containingType, currentType) ||
IsBaseTypeOf(containingType, currentType)))
{