From 94760792af3b1b6e7c716f13955ecf4b3988b96e Mon Sep 17 00:00:00 2001 From: Nicolas Dorier Date: Thu, 25 Jul 2024 22:46:02 +0900 Subject: [PATCH] Add parts of the UI to translate (#6119) --- BTCPayServer.Tests/SeleniumTester.cs | 1 + BTCPayServer.Tests/SeleniumTests.cs | 20 ++--- BTCPayServer.Tests/UtilitiesTests.cs | 87 +++++++++++++----- .../Components/MainNav/Default.cshtml | 88 +++++++++---------- .../Components/ThemeSwitch/Default.cshtml | 2 +- .../UIServerController.Translations.cs | 13 +++ .../Controllers/UIServerController.cs | 5 +- .../EditDictionaryViewModel.cs | 1 + BTCPayServer/Services/Translations.Default.cs | 80 +++++++++++++++++ BTCPayServer/Services/Translations.cs | 29 +++++- BTCPayServer/TagHelpers/TranslateTagHelper.cs | 32 +++++-- .../Views/Shared/CreateOrEditRole.cshtml | 2 +- .../Shared/Crowdfund/NavExtension.cshtml | 4 +- .../Shared/Crowdfund/UpdateCrowdfund.cshtml | 2 +- BTCPayServer/Views/Shared/ListRoles.cshtml | 2 +- .../Views/Shared/PayButton/Enable.cshtml | 2 +- .../Shared/PayButton/NavExtension.cshtml | 2 +- .../Views/Shared/PayButton/PayButton.cshtml | 2 +- .../Shared/PointOfSale/NavExtension.cshtml | 4 +- .../PointOfSale/UpdatePointOfSale.cshtml | 2 +- .../Views/Shared/Shopify/NavExtension.cshtml | 2 +- BTCPayServer/Views/Shared/_FormWrap.cshtml | 2 +- BTCPayServer/Views/UIAccount/SignedOut.cshtml | 2 +- BTCPayServer/Views/UIApps/CreateApp.cshtml | 2 +- BTCPayServer/Views/UIFido2/Create.cshtml | 2 +- .../Views/UIInvoice/CreateInvoice.cshtml | 2 +- BTCPayServer/Views/UIInvoice/Invoice.cshtml | 2 +- .../Views/UILNURL/EditLightningAddress.cshtml | 2 +- BTCPayServer/Views/UILNURLAuth/Create.cshtml | 2 +- .../Configure.cshtml | 2 +- .../ConfirmLightningPayout.cshtml | 2 +- .../LightningPayoutResult.cshtml | 2 +- BTCPayServer/Views/UIManage/APIKeys.cshtml | 2 +- BTCPayServer/Views/UIManage/AddApiKey.cshtml | 2 +- .../Views/UIManage/ChangePassword.cshtml | 2 +- .../Views/UIManage/EnableAuthenticator.cshtml | 2 +- .../UIManage/GenerateRecoveryCodes.cshtml | 4 +- BTCPayServer/Views/UIManage/Index.cshtml | 2 +- BTCPayServer/Views/UIManage/LoginCodes.cshtml | 2 +- .../UIManage/NotificationSettings.cshtml | 2 +- .../Views/UIManage/SetPassword.cshtml | 2 +- .../UIManage/TwoFactorAuthentication.cshtml | 2 +- .../Views/UINotifications/Index.cshtml | 2 +- .../Configure.cshtml | 2 +- .../EditPaymentRequest.cshtml | 2 +- .../ConfigureStorePayoutProcessors.cshtml | 2 +- .../UIPullPayment/EditPullPayment.cshtml | 2 +- BTCPayServer/Views/UIServer/Branding.cshtml | 6 +- .../UIServer/CLightningRestServices.cshtml | 2 +- .../Views/UIServer/ConfiguratorService.cshtml | 2 +- .../Views/UIServer/CreateDictionary.cshtml | 2 +- .../UIServer/CreateTemporaryFileUrl.cshtml | 2 +- BTCPayServer/Views/UIServer/CreateUser.cshtml | 2 +- .../EditAmazonS3StorageProvider.cshtml | 2 +- ...EditAzureBlobStorageStorageProvider.cshtml | 2 +- .../Views/UIServer/EditDictionary.cshtml | 7 +- .../EditFileSystemStorageProvider.cshtml | 2 +- ...itGoogleCloudStorageStorageProvider.cshtml | 2 +- BTCPayServer/Views/UIServer/Emails.cshtml | 2 +- BTCPayServer/Views/UIServer/Files.cshtml | 2 +- .../UIServer/LightningChargeServices.cshtml | 2 +- .../UIServer/LightningWalletServices.cshtml | 2 +- .../Views/UIServer/ListDictionaries.cshtml | 2 +- BTCPayServer/Views/UIServer/ListStores.cshtml | 4 +- BTCPayServer/Views/UIServer/ListUsers.cshtml | 2 +- .../Views/UIServer/LndSeedBackup.cshtml | 2 +- .../Views/UIServer/LndServices.cshtml | 2 +- BTCPayServer/Views/UIServer/Logs.cshtml | 4 +- .../Views/UIServer/Maintenance.cshtml | 4 +- BTCPayServer/Views/UIServer/P2PService.cshtml | 2 +- BTCPayServer/Views/UIServer/Policies.cshtml | 2 +- BTCPayServer/Views/UIServer/RPCService.cshtml | 2 +- BTCPayServer/Views/UIServer/SSHService.cshtml | 2 +- BTCPayServer/Views/UIServer/Services.cshtml | 4 +- BTCPayServer/Views/UIServer/Storage.cshtml | 2 +- BTCPayServer/Views/UIServer/User.cshtml | 2 +- .../UIStorePullPayments/NewPullPayment.cshtml | 2 +- .../UIStorePullPayments/PullPayments.cshtml | 2 +- .../Views/UIStores/CheckoutAppearance.cshtml | 2 +- .../Views/UIStores/CreateToken.cshtml | 4 +- BTCPayServer/Views/UIStores/Dashboard.cshtml | 2 +- .../Views/UIStores/GeneralSettings.cshtml | 16 ++-- BTCPayServer/Views/UIStores/Lightning.cshtml | 2 +- .../Views/UIStores/LightningSettings.cshtml | 2 +- .../Views/UIStores/ModifyWebhook.cshtml | 2 +- BTCPayServer/Views/UIStores/Rates.cshtml | 2 +- .../Views/UIStores/RequestPairing.cshtml | 4 +- .../Views/UIStores/StoreEmails.cshtml | 2 +- BTCPayServer/Views/UIStores/StoreUsers.cshtml | 2 +- .../Views/UIStores/TestWebhook.cshtml | 2 +- .../Views/UIStores/WalletSettings.cshtml | 2 +- BTCPayServer/Views/UIStores/Webhooks.cshtml | 2 +- .../Views/UIUserStores/CreateStore.cshtml | 2 +- .../Views/UIUserStores/ListStores.cshtml | 4 +- .../UIUserStores/_CreateStoreForm.cshtml | 2 +- .../Views/UIWallets/WalletLabels.cshtml | 4 +- 96 files changed, 381 insertions(+), 192 deletions(-) diff --git a/BTCPayServer.Tests/SeleniumTester.cs b/BTCPayServer.Tests/SeleniumTester.cs index e2f51b29d..7e50b3bd8 100644 --- a/BTCPayServer.Tests/SeleniumTester.cs +++ b/BTCPayServer.Tests/SeleniumTester.cs @@ -18,6 +18,7 @@ using NBitcoin; using NBitcoin.RPC; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; +using OpenQA.Selenium.Support.Extensions; using OpenQA.Selenium.Support.UI; using Xunit; diff --git a/BTCPayServer.Tests/SeleniumTests.cs b/BTCPayServer.Tests/SeleniumTests.cs index 65419ce2f..5aa2c6dbd 100644 --- a/BTCPayServer.Tests/SeleniumTests.cs +++ b/BTCPayServer.Tests/SeleniumTests.cs @@ -2063,7 +2063,7 @@ namespace BTCPayServer.Tests s.GoToStore(s.StoreId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0"); @@ -2108,7 +2108,7 @@ namespace BTCPayServer.Tests await s.Server.ExplorerNode.GenerateAsync(1); await s.FundStoreWallet(denomination: 50.0m); s.GoToStore(s.StoreId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0"); @@ -2122,7 +2122,7 @@ namespace BTCPayServer.Tests s.GoToStore(s.StoreId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP2"); s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).SendKeys("100.0"); @@ -2225,7 +2225,7 @@ namespace BTCPayServer.Tests s.GenerateWallet("BTC", "", true, true); s.GoToStore(s.StoreId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); s.Driver.FindElement(By.Id("Name")).SendKeys("External Test"); s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).SendKeys("0.001"); @@ -2276,7 +2276,7 @@ namespace BTCPayServer.Tests //Currently an onchain wallet is required to use the Lightning payouts feature.. s.GenerateWallet("BTC", "", true, true); s.GoToStore(newStore.storeId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); var paymentMethodOptions = s.Driver.FindElements(By.CssSelector("input[name='PayoutMethods']")); Assert.Equal(2, paymentMethodOptions.Count); @@ -2344,7 +2344,7 @@ namespace BTCPayServer.Tests //auto-approve pull payments s.GoToStore(StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true); s.Driver.FindElement(By.Id("Amount")).Clear(); @@ -2367,7 +2367,7 @@ namespace BTCPayServer.Tests // LNURL Withdraw support check with BTC denomination s.GoToStore(s.StoreId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true); s.Driver.FindElement(By.Id("Amount")).Clear(); @@ -2459,7 +2459,7 @@ namespace BTCPayServer.Tests } s.GoToStore(s.StoreId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), false); s.Driver.FindElement(By.Id("Amount")).Clear(); @@ -2499,7 +2499,7 @@ namespace BTCPayServer.Tests // LNURL Withdraw support check with SATS denomination s.GoToStore(s.StoreId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); s.Driver.FindElement(By.Id("Name")).SendKeys("PP SATS"); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true); s.Driver.FindElement(By.Id("Amount")).Clear(); @@ -3122,7 +3122,7 @@ namespace BTCPayServer.Tests // Check that pull payment has lightning option s.GoToStore(s.StoreId, StoreNavPages.PullPayments); - s.Driver.FindElement(By.Id("NewPullPayment")).Click(); + s.ClickPagePrimary(); Assert.Equal(PaymentTypes.LN.GetPaymentMethodId(cryptoCode), PaymentMethodId.Parse(Assert.Single(s.Driver.FindElements(By.CssSelector("input[name='PayoutMethods']"))).GetAttribute("value"))); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.FindElement(By.Id("Amount")).Clear(); diff --git a/BTCPayServer.Tests/UtilitiesTests.cs b/BTCPayServer.Tests/UtilitiesTests.cs index 9591870e5..543809a02 100644 --- a/BTCPayServer.Tests/UtilitiesTests.cs +++ b/BTCPayServer.Tests/UtilitiesTests.cs @@ -15,8 +15,10 @@ using BTCPayServer.Client; using BTCPayServer.Client.Models; using BTCPayServer.Controllers; using ExchangeSharp; +using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Intermediate; +using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using NBitcoin; @@ -27,6 +29,7 @@ using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Support.UI; using Xunit; using Xunit.Abstractions; +using static System.Net.Mime.MediaTypeNames; namespace BTCPayServer.Tests { @@ -267,6 +270,63 @@ retry: Thread.Sleep(200); } + class TranslatedKeyNodeWalker : IntermediateNodeWalker + { + private List _defaultTranslatedKeys; + private string _txt; + + public TranslatedKeyNodeWalker(List defaultTranslatedKeys) + { + _defaultTranslatedKeys = defaultTranslatedKeys; + } + + public TranslatedKeyNodeWalker(List defaultTranslatedKeys, string txt) : this(defaultTranslatedKeys) + { + _txt = txt; + } + + public override void VisitTagHelper(TagHelperIntermediateNode node) + { + if (node.TagName == "input") + { + foreach (var tagHelper in node.TagHelpers) + { + if (tagHelper.Name.EndsWith("TranslateTagHelper")) + { + var inner = ToString(node); + if (inner.Contains("type=\"submit\"")) + { + var m = Regex.Match(inner, "value=\"(.*?)\""); + if (m.Success) + { + _defaultTranslatedKeys.Add(m.Groups[1].Value); + } + } + } + } + return; + } + foreach (var tagHelper in node.TagHelpers) + { + if (tagHelper.Name.EndsWith("TranslateTagHelper")) + { + var htmlContent = node.FindDescendantNodes().FirstOrDefault(); + if (htmlContent is not null) + { + var inner = ToString(htmlContent); + _defaultTranslatedKeys.Add(inner); + } + } + } + base.VisitTagHelper(node); + } + + private string ToString(IntermediateNode? node) + { + return _txt.Substring(node.Source.Value.AbsoluteIndex, node.Source.Value.Length); + } + } + /// /// This utilities crawl through the cs files in search for /// Display attributes, then update Translations.Default to list them @@ -308,30 +368,17 @@ retry: defaultTranslatedKeys.Add(match.Groups[1].Value); } } - else if (txt.Contains("text-translate")) - { - filePath = filePath.Replace(Path.Combine(soldir.FullName, "BTCPayServer"), "/"); - var item = engine.FileSystem.GetItem(filePath); + + filePath = filePath.Replace(Path.Combine(soldir.FullName, "BTCPayServer"), "/"); + var item = engine.FileSystem.GetItem(filePath); - var node = (DocumentIntermediateNode)engine.Process(item).Items[typeof(DocumentIntermediateNode)]; - foreach (var n in node.FindDescendantNodes()) - { - foreach (var tagHelper in n.TagHelpers) - { - if (tagHelper.Name.EndsWith("TranslateTagHelper")) - { - var htmlContent = n.FindDescendantNodes().First(); - var inner = txt.Substring(htmlContent.Source.Value.AbsoluteIndex, htmlContent.Source.Value.Length); - defaultTranslatedKeys.Add(inner); - } - } - } - - } + var node = (DocumentIntermediateNode)engine.Process(item).Items[typeof(DocumentIntermediateNode)]; + var w = new TranslatedKeyNodeWalker(defaultTranslatedKeys, txt); + w.Visit(node); } } - defaultTranslatedKeys = defaultTranslatedKeys.Distinct().OrderBy(o => o).ToList(); + defaultTranslatedKeys = defaultTranslatedKeys.Select(d => d.Trim()).Distinct().OrderBy(o => o).ToList(); var path = Path.Combine(soldir.FullName, "BTCPayServer/Services/Translations.Default.cs"); var defaultTranslation = File.ReadAllText(path); var startIdx = defaultTranslation.IndexOf("\"\"\""); diff --git a/BTCPayServer/Components/MainNav/Default.cshtml b/BTCPayServer/Components/MainNav/Default.cshtml index c22cd6f0d..838fdea49 100644 --- a/BTCPayServer/Components/MainNav/Default.cshtml +++ b/BTCPayServer/Components/MainNav/Default.cshtml @@ -34,43 +34,43 @@ @if (ViewData.IsActivePage([StoreNavPages.General, StoreNavPages.Rates, StoreNavPages.CheckoutAppearance, StoreNavPages.Tokens, StoreNavPages.Users, StoreNavPages.Roles, StoreNavPages.Webhooks, StoreNavPages.PayoutProcessors, StoreNavPages.Emails, StoreNavPages.Forms])) { } @@ -79,9 +79,7 @@