diff --git a/Flow.Launcher.Core/Resource/AvailableLanguages.cs b/Flow.Launcher.Core/Resource/AvailableLanguages.cs index c385cd8e8..ecaecf646 100644 --- a/Flow.Launcher.Core/Resource/AvailableLanguages.cs +++ b/Flow.Launcher.Core/Resource/AvailableLanguages.cs @@ -30,7 +30,6 @@ namespace Flow.Launcher.Core.Resource public static Language Vietnamese = new Language("vi-vn", "Tiếng Việt"); public static Language Hebrew = new Language("he", "עברית"); - public static List GetAvailableLanguages() { List languages = new List @@ -63,5 +62,38 @@ namespace Flow.Launcher.Core.Resource }; return languages; } + + public static string GetSystemTranslation(string languageCode) + { + return languageCode switch + { + "en" => "System", + "zh-cn" => "系统", + "zh-tw" => "系統", + "uk-UA" => "Система", + "ru" => "Система", + "fr" => "Système", + "ja" => "システム", + "nl" => "Systeem", + "pl" => "System", + "da" => "System", + "de" => "System", + "ko" => "시스템", + "sr" => "Систем", + "pt-pt" => "Sistema", + "pt-br" => "Sistema", + "es" => "Sistema", + "es-419" => "Sistema", + "it" => "Sistema", + "nb-NO" => "System", + "sk" => "Systém", + "tr" => "Sistem", + "cs" => "Systém", + "ar" => "النظام", + "vi-vn" => "Hệ thống", + "he" => "מערכת", + _ => "System", + }; + } } } diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index de066dda1..884276f03 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -19,23 +19,52 @@ namespace Flow.Launcher.Core.Resource { public Settings Settings { get; set; } private const string Folder = "Languages"; + private const string DefaultLanguageCode = "en"; private const string DefaultFile = "en.xaml"; private const string Extension = ".xaml"; private readonly List _languageDirectories = new List(); private readonly List _oldResources = new List(); + private readonly string SystemLanguageCode; public Internationalization() { AddFlowLauncherLanguageDirectory(); + SystemLanguageCode = GetSystemLanguageCodeAtStartup(); } - private void AddFlowLauncherLanguageDirectory() { var directory = Path.Combine(Constant.ProgramDirectory, Folder); _languageDirectories.Add(directory); } + private static string GetSystemLanguageCodeAtStartup() + { + var availableLanguages = AvailableLanguages.GetAvailableLanguages(); + + // Retrieve the language identifiers for the current culture. + // ChangeLanguage method overrides the CultureInfo.CurrentCulture, so this needs to + // be called at startup in order to get the correct lang code of system. + var currentCulture = CultureInfo.CurrentCulture; + var twoLetterCode = currentCulture.TwoLetterISOLanguageName; + var threeLetterCode = currentCulture.ThreeLetterISOLanguageName; + var fullName = currentCulture.Name; + + // Try to find a match in the available languages list + foreach (var language in availableLanguages) + { + var languageCode = language.LanguageCode; + + if (string.Equals(languageCode, twoLetterCode, StringComparison.OrdinalIgnoreCase) || + string.Equals(languageCode, threeLetterCode, StringComparison.OrdinalIgnoreCase) || + string.Equals(languageCode, fullName, StringComparison.OrdinalIgnoreCase)) + { + return languageCode; + } + } + + return DefaultLanguageCode; + } internal void AddPluginLanguageDirectories(IEnumerable plugins) { @@ -69,8 +98,18 @@ namespace Flow.Launcher.Core.Resource public void ChangeLanguage(string languageCode) { languageCode = languageCode.NonNull(); - Language language = GetLanguageByLanguageCode(languageCode); - ChangeLanguage(language); + + // Get actual language if language code is system + var isSystem = false; + if (languageCode == Constant.SystemLanguageCode) + { + languageCode = SystemLanguageCode; + isSystem = true; + } + + // Get language by language code and change language + var language = GetLanguageByLanguageCode(languageCode); + ChangeLanguage(language, isSystem); } private Language GetLanguageByLanguageCode(string languageCode) @@ -88,11 +127,10 @@ namespace Flow.Launcher.Core.Resource } } - public void ChangeLanguage(Language language) + private void ChangeLanguage(Language language, bool isSystem) { language = language.NonNull(); - RemoveOldLanguageFiles(); if (language != AvailableLanguages.English) { @@ -104,7 +142,7 @@ namespace Flow.Launcher.Core.Resource CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture; // Raise event after culture is set - Settings.Language = language.LanguageCode; + Settings.Language = isSystem ? Constant.SystemLanguageCode : language.LanguageCode; _ = Task.Run(() => { UpdatePluginMetadataTranslations(); @@ -168,7 +206,9 @@ namespace Flow.Launcher.Core.Resource public List LoadAvailableLanguages() { - return AvailableLanguages.GetAvailableLanguages(); + var list = AvailableLanguages.GetAvailableLanguages(); + list.Insert(0, new Language(Constant.SystemLanguageCode, AvailableLanguages.GetSystemTranslation(SystemLanguageCode))); + return list; } public string GetTranslation(string key) diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs index 2889e5ec7..c86ed4324 100644 --- a/Flow.Launcher.Infrastructure/Constant.cs +++ b/Flow.Launcher.Infrastructure/Constant.cs @@ -52,5 +52,7 @@ namespace Flow.Launcher.Infrastructure public const string SponsorPage = "https://github.com/sponsors/Flow-Launcher"; public const string GitHub = "https://github.com/Flow-Launcher/Flow.Launcher"; public const string Docs = "https://flowlauncher.com/docs"; + + public const string SystemLanguageCode = "system"; } } diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 3e43e3d32..2a9d901fa 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -25,7 +25,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings _storage.Save(); } - private string language = "en"; + private string language = Constant.SystemLanguageCode; private string _theme = Constant.DefaultTheme; public string Hotkey { get; set; } = $"{KeyConstant.Alt} + {KeyConstant.Space}"; public string OpenResultModifiers { get; set; } = KeyConstant.Alt; diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index e311a0b94..00b97e114 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -41,9 +41,36 @@ namespace Flow.Launcher.Plugin.Program "uninst000.exe", "uninstall.exe" }; - // For cases when the uninstaller is named like "Uninstall Program Name.exe" - private const string CommonUninstallerPrefix = "uninstall"; - private const string CommonUninstallerSuffix = ".exe"; + private static readonly string[] commonUninstallerPrefixs = + { + "uninstall",//en + "卸载",//zh-cn + "卸載",//zh-tw + "видалити",//uk-UA + "удалить",//ru + "désinstaller",//fr + "アンインストール",//ja + "deïnstalleren",//nl + "odinstaluj",//pl + "afinstallere",//da + "deinstallieren",//de + "삭제",//ko + "деинсталирај",//sr + "desinstalar",//pt-pt + "desinstalar",//pt-br + "desinstalar",//es + "desinstalar",//es-419 + "disinstallare",//it + "avinstallere",//nb-NO + "odinštalovať",//sk + "kaldır",//tr + "odinstalovat",//cs + "إلغاء التثبيت",//ar + "gỡ bỏ",//vi-vn + "הסרה"//he + }; + private const string ExeUninstallerSuffix = ".exe"; + private const string InkUninstallerSuffix = ".lnk"; static Main() { @@ -96,10 +123,33 @@ namespace Flow.Launcher.Plugin.Program { if (!_settings.HideUninstallers) return true; if (program is not Win32 win32) return true; + + // First check the executable path var fileName = Path.GetFileName(win32.ExecutablePath); - return !commonUninstallerNames.Contains(fileName, StringComparer.OrdinalIgnoreCase) && - !(fileName.StartsWith(CommonUninstallerPrefix, StringComparison.OrdinalIgnoreCase) && - fileName.EndsWith(CommonUninstallerSuffix, StringComparison.OrdinalIgnoreCase)); + // For cases when the uninstaller is named like "uninst.exe" + if (commonUninstallerNames.Contains(fileName, StringComparer.OrdinalIgnoreCase)) return false; + // For cases when the uninstaller is named like "Uninstall Program Name.exe" + foreach (var prefix in commonUninstallerPrefixs) + { + if (fileName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) && + fileName.EndsWith(ExeUninstallerSuffix, StringComparison.OrdinalIgnoreCase)) + return false; + } + + // Second check the lnk path + if (!string.IsNullOrEmpty(win32.LnkResolvedPath)) + { + var inkFileName = Path.GetFileName(win32.FullPath); + // For cases when the uninstaller is named like "Uninstall Program Name.ink" + foreach (var prefix in commonUninstallerPrefixs) + { + if (inkFileName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) && + inkFileName.EndsWith(InkUninstallerSuffix, StringComparison.OrdinalIgnoreCase)) + return false; + } + } + + return true; } public async Task InitAsync(PluginInitContext context)