diff --git a/app/MindWork AI Studio/Layout/MainLayout.razor.cs b/app/MindWork AI Studio/Layout/MainLayout.razor.cs
index 4c45a3b9..04abf62c 100644
--- a/app/MindWork AI Studio/Layout/MainLayout.razor.cs
+++ b/app/MindWork AI Studio/Layout/MainLayout.razor.cs
@@ -79,6 +79,12 @@ public partial class MainLayout : LayoutComponentBase, IMessageBusReceiver, IDis
SettingsManager.DataDirectory = dataDir;
Directory.CreateDirectory(SettingsManager.DataDirectory);
+ //
+ // Read the user language from Rust:
+ //
+ var userLanguage = await this.RustService.ReadUserLanguage();
+ this.Logger.LogInformation($"The user language is: '{userLanguage}'");
+
// Ensure that all settings are loaded:
await this.SettingsManager.LoadSettings();
diff --git a/app/MindWork AI Studio/Pages/About.razor b/app/MindWork AI Studio/Pages/About.razor
index cfc2e559..32c8b5df 100644
--- a/app/MindWork AI Studio/Pages/About.razor
+++ b/app/MindWork AI Studio/Pages/About.razor
@@ -113,6 +113,7 @@
+
diff --git a/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua b/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua
index ab05f0bc..634c8e74 100644
--- a/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua
+++ b/app/MindWork AI Studio/Plugins/languages/de-de-43065dbc-78d0-45b7-92be-f14c2926e2dc/plugin.lua
@@ -40,6 +40,10 @@ IS_MAINTAINED = true
-- When the plugin is deprecated, this message will be shown to users:
DEPRECATION_MESSAGE = ""
+-- The IETF BCP 47 tag for the language. It's the ISO 639 language
+-- code followed by the ISO 3166-1 country code:
+IETF_TAG = "de-DE"
+
UI_TEXT_CONTENT = {
HOME = CONTENT_HOME,
}
diff --git a/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua b/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua
index d6c98d49..78f66474 100644
--- a/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua
+++ b/app/MindWork AI Studio/Plugins/languages/en-us-97dfb1ba-50c4-4440-8dfa-6575daf543c8/plugin.lua
@@ -40,6 +40,10 @@ IS_MAINTAINED = true
-- When the plugin is deprecated, this message will be shown to users:
DEPRECATION_MESSAGE = ""
+-- The IETF BCP 47 tag for the language. It's the ISO 639 language
+-- code followed by the ISO 3166-1 country code:
+IETF_TAG = "en-US"
+
UI_TEXT_CONTENT = {
HOME = CONTENT_HOME,
}
diff --git a/app/MindWork AI Studio/Tools/PluginSystem/PluginLanguage.cs b/app/MindWork AI Studio/Tools/PluginSystem/PluginLanguage.cs
index e39a4813..384d81eb 100644
--- a/app/MindWork AI Studio/Tools/PluginSystem/PluginLanguage.cs
+++ b/app/MindWork AI Studio/Tools/PluginSystem/PluginLanguage.cs
@@ -6,12 +6,16 @@ public sealed class PluginLanguage : PluginBase, ILanguagePlugin
{
private readonly Dictionary content = [];
private readonly List otherLanguagePlugins = [];
+ private readonly string langCultureTag;
private ILanguagePlugin? baseLanguage;
public PluginLanguage(bool isInternal, LuaState state, PluginType type) : base(isInternal, state, type)
{
- if (this.TryInitUITextContent(out var issue, out var readContent))
+ if(!this.TryInitIETFTag(out var issue, out this.langCultureTag))
+ this.pluginIssues.Add(issue);
+
+ if (this.TryInitUITextContent(out issue, out var readContent))
this.content = readContent;
else
this.pluginIssues.Add(issue);
@@ -65,4 +69,62 @@ public sealed class PluginLanguage : PluginBase, ILanguagePlugin
value = string.Empty;
return false;
}
+
+ ///
+ /// Tries to initialize the IETF tag.
+ ///
+ /// The error message, when the IETF tag could not be read.
+ /// The read IETF tag.
+ /// True, when the IETF tag could be read, false otherwise.
+ private bool TryInitIETFTag(out string message, out string readLangCultureTag)
+ {
+ if (!this.state.Environment["IETF_TAG"].TryRead(out readLangCultureTag))
+ {
+ message = "The field IETF_TAG does not exist or is not a valid string.";
+ readLangCultureTag = string.Empty;
+ return false;
+ }
+
+ if (string.IsNullOrWhiteSpace(readLangCultureTag))
+ {
+ message = "The field IETF_TAG is empty. Use a valid IETF tag like 'en-US'. The first part is the language, the second part is the country code.";
+ readLangCultureTag = string.Empty;
+ return false;
+ }
+
+ if (readLangCultureTag.Length != 5)
+ {
+ message = "The field IETF_TAG is not a valid IETF tag. Use a valid IETF tag like 'en-US'. The first part is the language, the second part is the country code.";
+ readLangCultureTag = string.Empty;
+ return false;
+ }
+
+ if (readLangCultureTag[2] != '-')
+ {
+ message = "The field IETF_TAG is not a valid IETF tag. Use a valid IETF tag like 'en-US'. The first part is the language, the second part is the country code.";
+ readLangCultureTag = string.Empty;
+ return false;
+ }
+
+ // Check the first part consists of only lower case letters:
+ for (var i = 0; i < 2; i++)
+ if (!char.IsLower(readLangCultureTag[i]))
+ {
+ message = "The field IETF_TAG is not a valid IETF tag. Use a valid IETF tag like 'en-US'. The first part is the language, the second part is the country code.";
+ readLangCultureTag = string.Empty;
+ return false;
+ }
+
+ // Check the second part consists of only upper case letters:
+ for (var i = 3; i < 5; i++)
+ if (!char.IsUpper(readLangCultureTag[i]))
+ {
+ message = "The field IETF_TAG is not a valid IETF tag. Use a valid IETF tag like 'en-US'. The first part is the language, the second part is the country code.";
+ readLangCultureTag = string.Empty;
+ return false;
+ }
+
+ message = string.Empty;
+ return true;
+ }
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Tools/Services/RustService.OS.cs b/app/MindWork AI Studio/Tools/Services/RustService.OS.cs
new file mode 100644
index 00000000..215b3a02
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/Services/RustService.OS.cs
@@ -0,0 +1,16 @@
+namespace AIStudio.Tools.Services;
+
+public sealed partial class RustService
+{
+ public async Task ReadUserLanguage()
+ {
+ var response = await this.http.GetAsync("/system/language");
+ if (!response.IsSuccessStatusCode)
+ {
+ this.logger!.LogError($"Failed to read the user language from Rust: '{response.StatusCode}'");
+ return string.Empty;
+ }
+
+ return await response.Content.ReadAsStringAsync();
+ }
+}
\ No newline at end of file
diff --git a/runtime/Cargo.lock b/runtime/Cargo.lock
index 2ff68b78..38144bea 100644
--- a/runtime/Cargo.lock
+++ b/runtime/Cargo.lock
@@ -2684,6 +2684,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
+ "sys-locale",
"tauri",
"tauri-build",
"tauri-plugin-window-state",
@@ -4759,6 +4760,15 @@ dependencies = [
"syn 2.0.93",
]
+[[package]]
+name = "sys-locale"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "system-configuration"
version = "0.5.1"
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index 61e62fbb..5f075adf 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -36,6 +36,7 @@ rcgen = { version = "0.13.2", features = ["pem"] }
file-format = "0.26.0"
calamine = "0.26.1"
pdfium-render = "0.8.29"
+sys-locale = "0.3.2"
# Fixes security vulnerability downstream, where the upstream is not fixed yet:
url = "2.5"
diff --git a/runtime/src/environment.rs b/runtime/src/environment.rs
index 53e8f8fe..af3435b1 100644
--- a/runtime/src/environment.rs
+++ b/runtime/src/environment.rs
@@ -1,5 +1,6 @@
use std::sync::OnceLock;
use rocket::get;
+use sys_locale::get_locale;
use crate::api_token::APIToken;
/// The data directory where the application stores its data.
@@ -34,4 +35,12 @@ pub fn is_dev() -> bool {
/// Returns true if the application is running in production mode.
pub fn is_prod() -> bool {
!is_dev()
+}
+
+#[get("/system/language")]
+pub fn read_user_language(_token: APIToken) -> String {
+ get_locale().unwrap_or_else(|| {
+ log::warn!("Could not determine the system language. Use default 'en-US'.");
+ String::from("en-US")
+ })
}
\ No newline at end of file
diff --git a/runtime/src/runtime_api.rs b/runtime/src/runtime_api.rs
index 0f383cc1..bf3fa249 100644
--- a/runtime/src/runtime_api.rs
+++ b/runtime/src/runtime_api.rs
@@ -77,6 +77,7 @@ pub fn start_runtime_api() {
crate::secret::delete_secret,
crate::environment::get_data_directory,
crate::environment::get_config_directory,
+ crate::environment::read_user_language,
crate::file_data::extract_data,
crate::log::get_log_paths,
])