Add parts of the UI to translate (#6119)

This commit is contained in:
Nicolas Dorier
2024-07-25 22:46:02 +09:00
committed by GitHub
parent 50dafd2452
commit 94760792af
96 changed files with 381 additions and 192 deletions

View File

@@ -18,6 +18,7 @@ using NBitcoin;
using NBitcoin.RPC; using NBitcoin.RPC;
using OpenQA.Selenium; using OpenQA.Selenium;
using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.Extensions;
using OpenQA.Selenium.Support.UI; using OpenQA.Selenium.Support.UI;
using Xunit; using Xunit;

View File

@@ -2063,7 +2063,7 @@ namespace BTCPayServer.Tests
s.GoToStore(s.StoreId, StoreNavPages.PullPayments); 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("Name")).SendKeys("PP1");
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();
s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0"); s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0");
@@ -2108,7 +2108,7 @@ namespace BTCPayServer.Tests
await s.Server.ExplorerNode.GenerateAsync(1); await s.Server.ExplorerNode.GenerateAsync(1);
await s.FundStoreWallet(denomination: 50.0m); await s.FundStoreWallet(denomination: 50.0m);
s.GoToStore(s.StoreId, StoreNavPages.PullPayments); 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("Name")).SendKeys("PP1");
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();
s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0"); s.Driver.FindElement(By.Id("Amount")).SendKeys("99.0");
@@ -2122,7 +2122,7 @@ namespace BTCPayServer.Tests
s.GoToStore(s.StoreId, StoreNavPages.PullPayments); 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("Name")).SendKeys("PP2");
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();
s.Driver.FindElement(By.Id("Amount")).SendKeys("100.0"); s.Driver.FindElement(By.Id("Amount")).SendKeys("100.0");
@@ -2225,7 +2225,7 @@ namespace BTCPayServer.Tests
s.GenerateWallet("BTC", "", true, true); s.GenerateWallet("BTC", "", true, true);
s.GoToStore(s.StoreId, StoreNavPages.PullPayments); 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("Name")).SendKeys("External Test");
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();
s.Driver.FindElement(By.Id("Amount")).SendKeys("0.001"); 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.. //Currently an onchain wallet is required to use the Lightning payouts feature..
s.GenerateWallet("BTC", "", true, true); s.GenerateWallet("BTC", "", true, true);
s.GoToStore(newStore.storeId, StoreNavPages.PullPayments); 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']")); var paymentMethodOptions = s.Driver.FindElements(By.CssSelector("input[name='PayoutMethods']"));
Assert.Equal(2, paymentMethodOptions.Count); Assert.Equal(2, paymentMethodOptions.Count);
@@ -2344,7 +2344,7 @@ namespace BTCPayServer.Tests
//auto-approve pull payments //auto-approve pull payments
s.GoToStore(StoreNavPages.PullPayments); s.GoToStore(StoreNavPages.PullPayments);
s.Driver.FindElement(By.Id("NewPullPayment")).Click(); s.ClickPagePrimary();
s.Driver.FindElement(By.Id("Name")).SendKeys("PP1"); s.Driver.FindElement(By.Id("Name")).SendKeys("PP1");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true);
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();
@@ -2367,7 +2367,7 @@ namespace BTCPayServer.Tests
// LNURL Withdraw support check with BTC denomination // LNURL Withdraw support check with BTC denomination
s.GoToStore(s.StoreId, StoreNavPages.PullPayments); 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("Name")).SendKeys("PP1");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true);
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();
@@ -2459,7 +2459,7 @@ namespace BTCPayServer.Tests
} }
s.GoToStore(s.StoreId, StoreNavPages.PullPayments); 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("Name")).SendKeys("PP1");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), false); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), false);
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();
@@ -2499,7 +2499,7 @@ namespace BTCPayServer.Tests
// LNURL Withdraw support check with SATS denomination // LNURL Withdraw support check with SATS denomination
s.GoToStore(s.StoreId, StoreNavPages.PullPayments); 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.FindElement(By.Id("Name")).SendKeys("PP SATS");
s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true); s.Driver.SetCheckbox(By.Id("AutoApproveClaims"), true);
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();
@@ -3122,7 +3122,7 @@ namespace BTCPayServer.Tests
// Check that pull payment has lightning option // Check that pull payment has lightning option
s.GoToStore(s.StoreId, StoreNavPages.PullPayments); 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"))); 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("Name")).SendKeys("PP1");
s.Driver.FindElement(By.Id("Amount")).Clear(); s.Driver.FindElement(By.Id("Amount")).Clear();

View File

@@ -15,8 +15,10 @@ using BTCPayServer.Client;
using BTCPayServer.Client.Models; using BTCPayServer.Client.Models;
using BTCPayServer.Controllers; using BTCPayServer.Controllers;
using ExchangeSharp; using ExchangeSharp;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Intermediate; using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using NBitcoin; using NBitcoin;
@@ -27,6 +29,7 @@ using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI; using OpenQA.Selenium.Support.UI;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
using static System.Net.Mime.MediaTypeNames;
namespace BTCPayServer.Tests namespace BTCPayServer.Tests
{ {
@@ -267,6 +270,63 @@ retry:
Thread.Sleep(200); Thread.Sleep(200);
} }
class TranslatedKeyNodeWalker : IntermediateNodeWalker
{
private List<string> _defaultTranslatedKeys;
private string _txt;
public TranslatedKeyNodeWalker(List<string> defaultTranslatedKeys)
{
_defaultTranslatedKeys = defaultTranslatedKeys;
}
public TranslatedKeyNodeWalker(List<string> 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<HtmlContentIntermediateNode>().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);
}
}
/// <summary> /// <summary>
/// This utilities crawl through the cs files in search for /// This utilities crawl through the cs files in search for
/// Display attributes, then update Translations.Default to list them /// Display attributes, then update Translations.Default to list them
@@ -308,30 +368,17 @@ retry:
defaultTranslatedKeys.Add(match.Groups[1].Value); defaultTranslatedKeys.Add(match.Groups[1].Value);
} }
} }
else if (txt.Contains("text-translate"))
{ filePath = filePath.Replace(Path.Combine(soldir.FullName, "BTCPayServer"), "/");
filePath = filePath.Replace(Path.Combine(soldir.FullName, "BTCPayServer"), "/"); var item = engine.FileSystem.GetItem(filePath);
var item = engine.FileSystem.GetItem(filePath);
var node = (DocumentIntermediateNode)engine.Process(item).Items[typeof(DocumentIntermediateNode)]; var node = (DocumentIntermediateNode)engine.Process(item).Items[typeof(DocumentIntermediateNode)];
foreach (var n in node.FindDescendantNodes<TagHelperIntermediateNode>()) var w = new TranslatedKeyNodeWalker(defaultTranslatedKeys, txt);
{ w.Visit(node);
foreach (var tagHelper in n.TagHelpers)
{
if (tagHelper.Name.EndsWith("TranslateTagHelper"))
{
var htmlContent = n.FindDescendantNodes<HtmlContentIntermediateNode>().First();
var inner = txt.Substring(htmlContent.Source.Value.AbsoluteIndex, htmlContent.Source.Value.Length);
defaultTranslatedKeys.Add(inner);
}
}
}
}
} }
} }
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 path = Path.Combine(soldir.FullName, "BTCPayServer/Services/Translations.Default.cs");
var defaultTranslation = File.ReadAllText(path); var defaultTranslation = File.ReadAllText(path);
var startIdx = defaultTranslation.IndexOf("\"\"\""); var startIdx = defaultTranslation.IndexOf("\"\"\"");

View File

@@ -34,43 +34,43 @@
<li class="nav-item" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.Dashboard))" asp-area="" asp-controller="UIStores" asp-action="Dashboard" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Dashboard)"> <a id="StoreNav-@(nameof(StoreNavPages.Dashboard))" asp-area="" asp-controller="UIStores" asp-action="Dashboard" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Dashboard)">
<vc:icon symbol="nav-dashboard"/> <vc:icon symbol="nav-dashboard"/>
<span>Dashboard</span> <span text-translate="true">Dashboard</span>
</a> </a>
</li> </li>
<li class="nav-item" permission="@Policies.CanViewStoreSettings"> <li class="nav-item" permission="@Policies.CanViewStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.General))" asp-area="" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.General)"> <a id="StoreNav-@(nameof(StoreNavPages.General))" asp-area="" asp-controller="UIStores" asp-action="GeneralSettings" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.General)">
<vc:icon symbol="nav-store-settings"/> <vc:icon symbol="nav-store-settings"/>
<span>Settings</span> <span text-translate="true">Settings</span>
</a> </a>
</li> </li>
@if (ViewData.IsActivePage([StoreNavPages.General, StoreNavPages.Rates, StoreNavPages.CheckoutAppearance, StoreNavPages.Tokens, StoreNavPages.Users, StoreNavPages.Roles, StoreNavPages.Webhooks, StoreNavPages.PayoutProcessors, StoreNavPages.Emails, StoreNavPages.Forms])) @if (ViewData.IsActivePage([StoreNavPages.General, StoreNavPages.Rates, StoreNavPages.CheckoutAppearance, StoreNavPages.Tokens, StoreNavPages.Users, StoreNavPages.Roles, StoreNavPages.Webhooks, StoreNavPages.PayoutProcessors, StoreNavPages.Emails, StoreNavPages.Forms]))
{ {
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.Rates))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Rates)" asp-controller="UIStores" asp-action="Rates" asp-route-storeId="@Model.Store.Id">Rates</a> <a id="StoreNav-@(nameof(StoreNavPages.Rates))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Rates)" asp-controller="UIStores" asp-action="Rates" asp-route-storeId="@Model.Store.Id" text-translate="true">Rates</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.CheckoutAppearance))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.CheckoutAppearance)" asp-controller="UIStores" asp-action="CheckoutAppearance" asp-route-storeId="@Model.Store.Id">Checkout Appearance</a> <a id="StoreNav-@(nameof(StoreNavPages.CheckoutAppearance))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.CheckoutAppearance)" asp-controller="UIStores" asp-action="CheckoutAppearance" asp-route-storeId="@Model.Store.Id" text-translate="true">Checkout Appearance</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.Tokens))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Tokens)" asp-controller="UIStores" asp-action="ListTokens" asp-route-storeId="@Model.Store.Id">Access Tokens</a> <a id="StoreNav-@(nameof(StoreNavPages.Tokens))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Tokens)" asp-controller="UIStores" asp-action="ListTokens" asp-route-storeId="@Model.Store.Id" text-translate="true">Access Tokens</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.Users))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Users)" asp-controller="UIStores" asp-action="StoreUsers" asp-route-storeId="@Model.Store.Id">Users</a> <a id="StoreNav-@(nameof(StoreNavPages.Users))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Users)" asp-controller="UIStores" asp-action="StoreUsers" asp-route-storeId="@Model.Store.Id" text-translate="true">Users</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.Roles))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Roles)" asp-controller="UIStores" asp-action="ListRoles" asp-route-storeId="@Model.Store.Id">Roles</a> <a id="StoreNav-@(nameof(StoreNavPages.Roles))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Roles)" asp-controller="UIStores" asp-action="ListRoles" asp-route-storeId="@Model.Store.Id" text-translate="true">Roles</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.Webhooks))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Webhooks)" asp-controller="UIStores" asp-action="Webhooks" asp-route-storeId="@Model.Store.Id">Webhooks</a> <a id="StoreNav-@(nameof(StoreNavPages.Webhooks))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Webhooks)" asp-controller="UIStores" asp-action="Webhooks" asp-route-storeId="@Model.Store.Id" text-translate="true">Webhooks</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.PayoutProcessors))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PayoutProcessors)" asp-controller="UIPayoutProcessors" asp-action="ConfigureStorePayoutProcessors" asp-route-storeId="@Model.Store.Id">Payout Processors</a> <a id="StoreNav-@(nameof(StoreNavPages.PayoutProcessors))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PayoutProcessors)" asp-controller="UIPayoutProcessors" asp-action="ConfigureStorePayoutProcessors" asp-route-storeId="@Model.Store.Id" text-translate="true">Payout Processors</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.Emails))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Emails)" asp-controller="UIStores" asp-action="StoreEmailSettings" asp-route-storeId="@Model.Store.Id">Emails</a> <a id="StoreNav-@(nameof(StoreNavPages.Emails))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Emails)" asp-controller="UIStores" asp-action="StoreEmailSettings" asp-route-storeId="@Model.Store.Id" text-translate="true">Emails</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyStoreSettings">
<a id="StoreNav-@(nameof(StoreNavPages.Forms))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Forms)" asp-controller="UIForms" asp-action="FormsList" asp-route-storeId="@Model.Store.Id">Forms</a> <a id="StoreNav-@(nameof(StoreNavPages.Forms))" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Forms)" asp-controller="UIForms" asp-action="FormsList" asp-route-storeId="@Model.Store.Id" text-translate="true">Forms</a>
</li> </li>
} }
<vc:ui-extension-point location="store-nav" model="@Model"/> <vc:ui-extension-point location="store-nav" model="@Model"/>
@@ -79,9 +79,7 @@
</div> </div>
<div class="accordion-item"> <div class="accordion-item">
<header class="accordion-header" id="Nav-Wallets-Header" permission="@Policies.CanModifyStoreSettings"> <header class="accordion-header" id="Nav-Wallets-Header" permission="@Policies.CanModifyStoreSettings">
<div class="accordion-button"> <div text-translate="true" class="accordion-button">Wallets</div>
Wallets
</div>
</header> </header>
<div id="Nav-Wallets" class="accordion-collapse" aria-labelledby="Nav-Wallets-Header" permission="@Policies.CanModifyStoreSettings"> <div id="Nav-Wallets" class="accordion-collapse" aria-labelledby="Nav-Wallets-Header" permission="@Policies.CanModifyStoreSettings">
<div class="accordion-body"> <div class="accordion-body">
@@ -157,7 +155,7 @@
<div class="accordion-item"> <div class="accordion-item">
<header class="accordion-header" id="Nav-Payments-Header"> <header class="accordion-header" id="Nav-Payments-Header">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Payments" aria-expanded="true" aria-controls="Nav-Payments"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Payments" aria-expanded="true" aria-controls="Nav-Payments">
Payments <span text-translate="true">Payments</span>
<vc:icon symbol="caret-down"/> <vc:icon symbol="caret-down"/>
</button> </button>
</header> </header>
@@ -167,25 +165,25 @@
<li class="nav-item" permission="@Policies.CanViewInvoices"> <li class="nav-item" permission="@Policies.CanViewInvoices">
<a asp-area="" asp-controller="UIInvoice" asp-action="ListInvoices" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActiveCategoryClass(typeof(InvoiceNavPages))" id="StoreNav-Invoices"> <a asp-area="" asp-controller="UIInvoice" asp-action="ListInvoices" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActiveCategoryClass(typeof(InvoiceNavPages))" id="StoreNav-Invoices">
<vc:icon symbol="nav-invoices"/> <vc:icon symbol="nav-invoices"/>
<span>Invoices</span> <span text-translate="true">Invoices</span>
</a> </a>
</li> </li>
<li class="nav-item" permission="@Policies.CanViewReports"> <li class="nav-item" permission="@Policies.CanViewReports">
<a asp-area="" asp-controller="UIReports" asp-action="StoreReports" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Reporting)" id="SectionNav-Reporting"> <a asp-area="" asp-controller="UIReports" asp-action="StoreReports" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Reporting)" id="SectionNav-Reporting">
<vc:icon symbol="nav-reporting" /> <vc:icon symbol="nav-reporting" />
<span>Reporting</span> <span text-translate="true">Reporting</span>
</a> </a>
</li> </li>
<li class="nav-item" permission="@Policies.CanViewPaymentRequests"> <li class="nav-item" permission="@Policies.CanViewPaymentRequests">
<a asp-area="" asp-controller="UIPaymentRequest" asp-action="GetPaymentRequests" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActiveCategoryClass(typeof(PaymentRequestsNavPages))" id="StoreNav-PaymentRequests"> <a asp-area="" asp-controller="UIPaymentRequest" asp-action="GetPaymentRequests" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActiveCategoryClass(typeof(PaymentRequestsNavPages))" id="StoreNav-PaymentRequests">
<vc:icon symbol="nav-payment-requests"/> <vc:icon symbol="nav-payment-requests"/>
<span>Requests</span> <span text-translate="true">Requests</span>
</a> </a>
</li> </li>
<li class="nav-item" permission="@Policies.CanViewPullPayments"> <li class="nav-item" permission="@Policies.CanViewPullPayments">
<a asp-area="" asp-controller="UIStorePullPayments" asp-action="PullPayments" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PullPayments)" id="StoreNav-PullPayments"> <a asp-area="" asp-controller="UIStorePullPayments" asp-action="PullPayments" asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PullPayments)" id="StoreNav-PullPayments">
<vc:icon symbol="nav-pull-payments"/> <vc:icon symbol="nav-pull-payments"/>
<span>Pull Payments</span> <span text-translate="true">Pull Payments</span>
</a> </a>
</li> </li>
<li class="nav-item" permission="@Policies.CanViewPayouts"> <li class="nav-item" permission="@Policies.CanViewPayouts">
@@ -194,7 +192,7 @@
asp-route-pullPaymentId="" asp-route-pullPaymentId=""
asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Payouts)" id="StoreNav-Payouts"> asp-route-storeId="@Model.Store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.Payouts)" id="StoreNav-Payouts">
<vc:icon symbol="nav-payouts"/> <vc:icon symbol="nav-payouts"/>
<span>Payouts</span> <span text-translate="true">Payouts</span>
</a> </a>
</li> </li>
</ul> </ul>
@@ -206,7 +204,7 @@
<div class="accordion-item"> <div class="accordion-item">
<header class="accordion-header" id="Nav-Plugins-Header"> <header class="accordion-header" id="Nav-Plugins-Header">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Plugins" aria-expanded="true" aria-controls="Nav-Plugins"> <button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#Nav-Plugins" aria-expanded="true" aria-controls="Nav-Plugins">
Plugins <span text-translate="true">Plugins</span>
<vc:icon symbol="caret-down"/> <vc:icon symbol="caret-down"/>
</button> </button>
</header> </header>
@@ -230,7 +228,7 @@
{ {
<vc:icon symbol="nav-plugins-manage" /> <vc:icon symbol="nav-plugins-manage" />
} }
<span>Manage Plugins</span> <span text-translate="true">Manage Plugins</span>
</a> </a>
</li> </li>
@if (Model.Store != null && Model.ArchivedAppsCount > 0) @if (Model.Store != null && Model.ArchivedAppsCount > 0)
@@ -274,11 +272,11 @@
@if (!PoliciesSettings.LockSubscription) @if (!PoliciesSettings.LockSubscription)
{ {
<li class="nav-item"> <li class="nav-item">
<a asp-area="" asp-controller="UIAccount" asp-action="Register" class="nav-link" id="Nav-Register">Register</a> <a asp-area="" asp-controller="UIAccount" asp-action="Register" class="nav-link" id="Nav-Register" text-translate="true">Register</a>
</li> </li>
} }
<li class="nav-item"> <li class="nav-item">
<a asp-area="" asp-controller="UIAccount" asp-action="Login" class="nav-link" id="Nav-Login">Log in</a> <a asp-area="" asp-controller="UIAccount" asp-action="Login" class="nav-link" id="Nav-Login" text-translate="true">Log in</a>
</li> </li>
</ul> </ul>
} }
@@ -289,47 +287,47 @@
<li class="nav-item" permission="@Policies.CanModifyServerSettings"> <li class="nav-item" permission="@Policies.CanModifyServerSettings">
<a asp-area="" asp-controller="UIServer" asp-action="Policies" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Policies)" id="Nav-ServerSettings"> <a asp-area="" asp-controller="UIServer" asp-action="Policies" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Policies)" id="Nav-ServerSettings">
<vc:icon symbol="nav-server-settings"/> <vc:icon symbol="nav-server-settings"/>
<span>Server Settings</span> <span text-translate="true">Server Settings</span>
</a> </a>
</li> </li>
@if (ViewData.IsActiveCategory(typeof(ServerNavPages)) && !ViewData.IsActivePage([ServerNavPages.Plugins])) @if (ViewData.IsActiveCategory(typeof(ServerNavPages)) && !ViewData.IsActivePage([ServerNavPages.Plugins]))
{ {
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Users" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Users)" asp-action="ListUsers">Users</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Users" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Users)" asp-action="ListUsers" text-translate="true">Users</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Roles" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Roles)" asp-action="ListRoles">Roles</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Roles" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Roles)" asp-action="ListRoles" text-translate="true">Roles</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Emails" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Emails)" asp-action="Emails">Email</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Emails" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Emails)" asp-action="Emails" text-translate="true">Email</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Services" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Services)" asp-action="Services">Services</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Services" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Services)" asp-action="Services" text-translate="true">Services</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Branding" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Branding)" asp-action="Branding">Branding</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Branding" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Branding)" asp-action="Branding" text-translate="true">Branding</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Translations" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Translations)" asp-action="ListDictionaries">Translations</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Translations" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Translations)" asp-action="ListDictionaries" text-translate="true">Translations</a>
</li> </li>
@if (BtcPayServerOptions.DockerDeployment) @if (BtcPayServerOptions.DockerDeployment)
{ {
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Maintenance" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Maintenance)" asp-action="Maintenance">Maintenance</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Maintenance" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Maintenance)" asp-action="Maintenance" text-translate="true">Maintenance</a>
</li> </li>
} }
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Logs" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Logs)" asp-action="LogsView">Logs</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Logs" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Logs)" asp-action="LogsView" text-translate="true">Logs</a>
</li> </li>
<li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings"> <li class="nav-item nav-item-sub" permission="@Policies.CanModifyServerSettings">
<a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Files" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Files)" asp-action="Files">Files</a> <a asp-controller="UIServer" id="SectionNav-@ServerNavPages.Files" class="nav-link @ViewData.ActivePageClass(ServerNavPages.Files)" asp-action="Files" text-translate="true">Files</a>
</li> </li>
} }
<vc:ui-extension-point location="server-nav" model="@Model"/> <vc:ui-extension-point location="server-nav" model="@Model"/>
<li class="nav-item dropup"> <li class="nav-item dropup">
<a class="nav-link @ViewData.ActivePageClass(ManageNavPages.Index)" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false" id="Nav-Account"> <a class="nav-link @ViewData.ActivePageClass(ManageNavPages.Index)" role="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false" id="Nav-Account">
<vc:icon symbol="nav-account"/> <vc:icon symbol="nav-account"/>
<span>Account</span> <span text-translate="true">Account</span>
</a> </a>
<ul class="dropdown-menu py-0 w-100" aria-labelledby="Nav-Account"> <ul class="dropdown-menu py-0 w-100" aria-labelledby="Nav-Account">
<li class="p-3 border-bottom d-flex align-items-center gap-2"> <li class="p-3 border-bottom d-flex align-items-center gap-2">
@@ -350,7 +348,7 @@
</strong> </strong>
@if (User.IsInRole(Roles.ServerAdmin)) @if (User.IsInRole(Roles.ServerAdmin))
{ {
<div class="text-secondary">Administrator</div> <div class="text-secondary" text-translate="true">Administrator</div>
} }
</div> </div>
</li> </li>
@@ -362,7 +360,7 @@
} }
<li class="py-1 px-3"> <li class="py-1 px-3">
<label class="d-flex align-items-center justify-content-between gap-3 nav-link"> <label class="d-flex align-items-center justify-content-between gap-3 nav-link">
<span class="fw-semibold">Hide Sensitive Info</span> <span class="fw-semibold" text-translate="true">Hide Sensitive Info</span>
<input id="HideSensitiveInfo" name="HideSensitiveInfo" type="checkbox" class="btcpay-toggle" /> <input id="HideSensitiveInfo" name="HideSensitiveInfo" type="checkbox" class="btcpay-toggle" />
</label> </label>
<script> <script>
@@ -371,12 +369,12 @@
</li> </li>
<li class="border-top py-1 px-3"> <li class="border-top py-1 px-3">
<a asp-area="" asp-controller="UIManage" asp-action="Index" class="nav-link" id="Nav-ManageAccount"> <a asp-area="" asp-controller="UIManage" asp-action="Index" class="nav-link" id="Nav-ManageAccount">
<span>Manage Account</span> <span text-translate="true">Manage Account</span>
</a> </a>
</li> </li>
<li class="border-top py-1 px-3"> <li class="border-top py-1 px-3">
<a asp-area="" asp-controller="UIAccount" asp-action="Logout" class="nav-link text-danger" id="Nav-Logout"> <a asp-area="" asp-controller="UIAccount" asp-action="Logout" class="nav-link text-danger" id="Nav-Logout">
<span>Logout</span> <span text-translate="true">Logout</span>
</a> </a>
</li> </li>
</ul> </ul>
@@ -384,19 +382,19 @@
@if (ViewData.IsActiveCategory(typeof(ManageNavPages)) || ViewData.IsActivePage([ManageNavPages.ChangePassword])) @if (ViewData.IsActiveCategory(typeof(ManageNavPages)) || ViewData.IsActivePage([ManageNavPages.ChangePassword]))
{ {
<li class="nav-item nav-item-sub"> <li class="nav-item nav-item-sub">
<a id="SectionNav-@ManageNavPages.ChangePassword.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.ChangePassword)" asp-controller="UIManage" asp-action="ChangePassword">Password</a> <a id="SectionNav-@ManageNavPages.ChangePassword.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.ChangePassword)" asp-controller="UIManage" asp-action="ChangePassword" text-translate="true">Password</a>
</li> </li>
<li class="nav-item nav-item-sub"> <li class="nav-item nav-item-sub">
<a id="SectionNav-@ManageNavPages.TwoFactorAuthentication.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.TwoFactorAuthentication)" asp-controller="UIManage" asp-action="TwoFactorAuthentication">Two-Factor Authentication</a> <a id="SectionNav-@ManageNavPages.TwoFactorAuthentication.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.TwoFactorAuthentication)" asp-controller="UIManage" asp-action="TwoFactorAuthentication" text-translate="true">Two-Factor Authentication</a>
</li> </li>
<li class="nav-item nav-item-sub"> <li class="nav-item nav-item-sub">
<a id="SectionNav-@ManageNavPages.APIKeys.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.APIKeys)" asp-controller="UIManage" asp-action="APIKeys">API Keys</a> <a id="SectionNav-@ManageNavPages.APIKeys.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.APIKeys)" asp-controller="UIManage" asp-action="APIKeys" text-translate="true">API Keys</a>
</li> </li>
<li class="nav-item nav-item-sub"> <li class="nav-item nav-item-sub">
<a id="SectionNav-@ManageNavPages.Notifications.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.Notifications)" asp-controller="UIManage" asp-action="NotificationSettings">Notifications</a> <a id="SectionNav-@ManageNavPages.Notifications.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.Notifications)" asp-controller="UIManage" asp-action="NotificationSettings" text-translate="true">Notifications</a>
</li> </li>
<li class="nav-item nav-item-sub"> <li class="nav-item nav-item-sub">
<a id="SectionNav-@ManageNavPages.LoginCodes.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.LoginCodes)" asp-controller="UIManage" asp-action="LoginCodes">Login Codes</a> <a id="SectionNav-@ManageNavPages.LoginCodes.ToString()" class="nav-link @ViewData.ActivePageClass(ManageNavPages.LoginCodes)" asp-controller="UIManage" asp-action="LoginCodes" text-translate="true">Login Codes</a>
</li> </li>
<vc:ui-extension-point location="user-nav" model="@Model" /> <vc:ui-extension-point location="user-nav" model="@Model" />
} }
@@ -405,7 +403,7 @@
<li class="nav-item"> <li class="nav-item">
<a href="@Model.ContactUrl" class="nav-link" id="Nav-ContactUs"> <a href="@Model.ContactUrl" class="nav-link" id="Nav-ContactUs">
<vc:icon symbol="nav-contact"/> <vc:icon symbol="nav-contact"/>
<span>Contact Us</span> <span text-translate="true">Contact Us</span>
</a> </a>
</li> </li>
} }

View File

@@ -1,7 +1,7 @@
@model BTCPayServer.Components.ThemeSwitch.ThemeSwitchViewModel @model BTCPayServer.Components.ThemeSwitch.ThemeSwitchViewModel
<div class="btcpay-theme-switch @Model.CssClass"> <div class="btcpay-theme-switch @Model.CssClass">
<span class="btcpay-theme-switch-label">Theme</span> <span class="btcpay-theme-switch-label" text-translate="true">Theme</span>
<div class="btcpay-theme-switch-themes"> <div class="btcpay-theme-switch-themes">
<button type="button" title="System" data-theme="system"><vc:icon symbol="themes-system"/></button> <button type="button" title="System" data-theme="system"><vc:icon symbol="themes-system"/></button>
<button type="button" title="Light" data-theme="light"><vc:icon symbol="themes-light"/></button> <button type="button" title="Light" data-theme="light"><vc:icon symbol="themes-light"/></button>

View File

@@ -7,6 +7,7 @@ using BTCPayServer.Models.ServerViewModels;
using BTCPayServer.Services; using BTCPayServer.Services;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Controllers namespace BTCPayServer.Controllers
{ {
@@ -78,6 +79,18 @@ namespace BTCPayServer.Controllers
var d = await this._localizer.GetDictionary(dictionary); var d = await this._localizer.GetDictionary(dictionary);
if (d is null) if (d is null)
return NotFound(); return NotFound();
if (Environment.CheatMode && viewModel.Command == "Fake")
{
var t = await _localizer.GetTranslations(dictionary);
var jobj = JObject.Parse(t.Translations.ToJsonFormat());
foreach (var prop in jobj.Properties())
{
prop.Value = "OK";
}
viewModel.Translations = Translations.CreateFromJson(jobj.ToString()).ToTextFormat();
}
if (!Translations.TryCreateFromText(viewModel.Translations, out var translations)) if (!Translations.TryCreateFromText(viewModel.Translations, out var translations))
{ {
ModelState.AddModelError(nameof(viewModel.Translations), "Syntax error"); ModelState.AddModelError(nameof(viewModel.Translations), "Syntax error");

View File

@@ -95,7 +95,8 @@ namespace BTCPayServer.Controllers
IHostApplicationLifetime applicationLifetime, IHostApplicationLifetime applicationLifetime,
IHtmlHelper html, IHtmlHelper html,
TransactionLinkProviders transactionLinkProviders, TransactionLinkProviders transactionLinkProviders,
LocalizerService localizer LocalizerService localizer,
BTCPayServerEnvironment environment
) )
{ {
_policiesSettings = policiesSettings; _policiesSettings = policiesSettings;
@@ -123,6 +124,7 @@ namespace BTCPayServer.Controllers
Html = html; Html = html;
_transactionLinkProviders = transactionLinkProviders; _transactionLinkProviders = transactionLinkProviders;
_localizer = localizer; _localizer = localizer;
Environment = environment;
} }
[HttpGet("server/stores")] [HttpGet("server/stores")]
@@ -325,6 +327,7 @@ namespace BTCPayServer.Controllers
public IHttpClientFactory HttpClientFactory { get; } public IHttpClientFactory HttpClientFactory { get; }
public IHostApplicationLifetime ApplicationLifetime { get; } public IHostApplicationLifetime ApplicationLifetime { get; }
public IHtmlHelper Html { get; } public IHtmlHelper Html { get; }
public BTCPayServerEnvironment Environment { get; }
[Route("server/policies")] [Route("server/policies")]
public async Task<IActionResult> Policies() public async Task<IActionResult> Policies()

View File

@@ -6,6 +6,7 @@ public class EditDictionaryViewModel
{ {
public string Translations { get; set; } public string Translations { get; set; }
public int Lines { get; set; } public int Lines { get; set; }
public string Command { get; set; }
internal EditDictionaryViewModel SetTranslations(Translations translations) internal EditDictionaryViewModel SetTranslations(Translations translations)
{ {

View File

@@ -11,13 +11,22 @@ namespace BTCPayServer.Services
// Please run it before release. // Please run it before release.
var knownTranslations = var knownTranslations =
""" """
Access Tokens
Account
Account key Account key
Account key path Account key path
Add additional fee (network fee) to invoice Add additional fee (network fee) to invoice
Add Address
Add Exchange Rate Spread Add Exchange Rate Spread
Add hop hints for private channels to the Lightning invoice Add hop hints for private channels to the Lightning invoice
Add Role
Add Service
Add User
Add Webhook
Additional Actions
Admin API access token Admin API access token
Admin must approve new users Admin must approve new users
Administrator
Allow anyone to create invoice Allow anyone to create invoice
Allow form for public use Allow form for public use
Allow payee to create invoices with custom amounts Allow payee to create invoices with custom amounts
@@ -27,10 +36,13 @@ Always include non-witness UTXO if available
Amazon S3 Amazon S3
Amount Amount
API Key API Key
API Keys
App App
App Name App Name
App Type App Type
Application Application
Approve
Archive this store
Authenticator code Authenticator code
Auto-detect language on checkout Auto-detect language on checkout
Automatically approve claims Automatically approve claims
@@ -40,12 +52,14 @@ Backend's language
Batch size Batch size
BIP39 Seed (12/24 word mnemonic phrase) or HD private key (xprv...) BIP39 Seed (12/24 word mnemonic phrase) or HD private key (xprv...)
Brand Color Brand Color
Branding
Buyer Email Buyer Email
Callback Notification URL Callback Notification URL
Can use hot wallet Can use hot wallet
Can use RPC import Can use RPC import
Celebrate payment with confetti Celebrate payment with confetti
Check releases on GitHub and notify when new BTCPay Server version is available Check releases on GitHub and notify when new BTCPay Server version is available
Checkout Appearance
Colors to rotate between with animation when a payment is made. One color per line. Colors to rotate between with animation when a payment is made. One color per line.
Confirm new password Confirm new password
Confirm password Confirm password
@@ -53,8 +67,20 @@ Connection string
Consider the invoice paid even if the paid amount is % less than expected Consider the invoice paid even if the paid amount is % less than expected
Consider the invoice settled when the payment transaction Consider the invoice settled when the payment transaction
Contact URL Contact URL
Contact Us
Contribution Perks Template Contribution Perks Template
Count all invoices created on the store as part of the goal Count all invoices created on the store as part of the goal
Create
Create a new app
Create Account
Create Form
Create Invoice
Create Pull Payment
Create Request
Create Store
Create Webhook
Create your account
Crowdfund
Currency Currency
Current password Current password
Custom CSS Custom CSS
@@ -62,10 +88,12 @@ Custom HTML title to display on Checkout page
Custom sound file for successful payment Custom sound file for successful payment
Custom Theme Extension Type Custom Theme Extension Type
Custom Theme File Custom Theme File
Dashboard
Default currency Default currency
Default language on checkout Default language on checkout
Default payment method on checkout Default payment method on checkout
Default role for users on a new store Default role for users on a new store
Delete this store
Derivation scheme Derivation scheme
Derivation scheme format Derivation scheme format
Description Description
@@ -92,6 +120,7 @@ Email
Email address Email address
Email confirmation required Email confirmation required
Email confirmed? Email confirmed?
Emails
Enable background animations on new payments Enable background animations on new payments
Enable Disqus Comments Enable Disqus Comments
Enable experimental features Enable experimental features
@@ -105,18 +134,27 @@ Enable tips
End date End date
Error Error
Expiration Date Expiration Date
Export
Extends the BTCPay Server Dark theme Extends the BTCPay Server Dark theme
Extends the BTCPay Server Light theme Extends the BTCPay Server Light theme
Featured Image URL Featured Image URL
Fee rate (sat/vB) Fee rate (sat/vB)
Files
Forgot password?
Form configuration (JSON) Form configuration (JSON)
Forms
Gap limit Gap limit
Generate
Generate API Key
Generate Key
Google Cloud Storage Google Cloud Storage
GRPC SSL Cipher suite (GRPC_SSL_CIPHER_SUITES) GRPC SSL Cipher suite (GRPC_SSL_CIPHER_SUITES)
Hide Sensitive Info
Image Image
Invoice currency Invoice currency
Invoice expires if the full amount has not been paid after Invoice expires if the full amount has not been paid after
Invoice metadata Invoice metadata
Invoices
Is administrator? Is administrator?
Is signing key Is signing key
Item Description Item Description
@@ -124,8 +162,15 @@ Keypad
Lightning node (LNURL Auth) Lightning node (LNURL Auth)
LNURL Classic Mode LNURL Classic Mode
Local File System Local File System
Log in
Login Codes
Logo Logo
Logout
Logs
Maintenance
Make Crowdfund Public Make Crowdfund Public
Manage Account
Manage Plugins
Master fingerprint Master fingerprint
Max sats Max sats
Memo Memo
@@ -133,6 +178,7 @@ Metadata
Min sats Min sats
Minimum acceptable expiration time for BOLT11 for refunds Minimum acceptable expiration time for BOLT11 for refunds
New password New password
Next
Non-admins can access the User Creation API Endpoint Non-admins can access the User Creation API Endpoint
Non-admins can create Hot Wallets for their Store Non-admins can create Hot Wallets for their Store
Non-admins can import Hot Wallets for their Store Non-admins can import Hot Wallets for their Store
@@ -140,6 +186,7 @@ Non-admins can use the Internal Lightning Node for their Store
Non-admins cannot access the User Creation API Endpoint Non-admins cannot access the User Creation API Endpoint
Notification Email Notification Email
Notification URL Notification URL
Notifications
Only enable the payment method after user explicitly chooses it Only enable the payment method after user explicitly chooses it
Optional seed passphrase Optional seed passphrase
Order Id Order Id
@@ -147,10 +194,17 @@ Override the block explorers used
Pair to Pair to
Password Password
Password (leave blank to generate invite-link) Password (leave blank to generate invite-link)
Pay Button
PayJoin BIP21 PayJoin BIP21
Payment
Payment invalid if transactions fails to confirm after invoice expiration Payment invalid if transactions fails to confirm after invoice expiration
Payments
Payout Methods Payout Methods
Payout Processors
Payouts
Plugin server Plugin server
Plugins
Point of Sale
Point of Sale Style Point of Sale Style
Policies Policies
Preferred Price Source Preferred Price Source
@@ -161,26 +215,41 @@ Profile Picture
PSBT content PSBT content
PSBT to combine with PSBT to combine with
Public Key Public Key
Pull Payments
Rate Rules Rate Rules
Rates
Recommended fee confirmation target blocks Recommended fee confirmation target blocks
Recovery Code Recovery Code
Redirect invoice to redirect url automatically after paid Redirect invoice to redirect url automatically after paid
Redirect URL Redirect URL
Regenerate code
Register
Remember me Remember me
Remember this machine Remember this machine
Reporting
Request contributor data on checkout Request contributor data on checkout
Request customer data on checkout Request customer data on checkout
Request Pairing
Requests
Reset goal every Reset goal every
REST Uri REST Uri
Role Role
Roles
Root fingerprint Root fingerprint
Save
Scope Scope
Search engines can index this site Search engines can index this site
Security device (FIDO2) Security device (FIDO2)
Select the Default Currency during Store Creation Select the Default Currency during Store Creation
Select the payout method used for refund Select the payout method used for refund
Send test webhook
Server Name Server Name
Server Settings
Services
Set Password
Settings
Shop Name Shop Name
Shopify
Show "Pay in wallet" button Show "Pay in wallet" button
Show a timer minutes before invoice expiration Show a timer minutes before invoice expiration
Show plugins in pre-release Show plugins in pre-release
@@ -197,7 +266,9 @@ Starting index
Store Store
Store Id Store Id
Store Name Store Name
Store Settings
Store Website Store Website
Submit
Subtract fees from amount Subtract fees from amount
Support URL Support URL
Supported Transaction Currencies Supported Transaction Currencies
@@ -206,18 +277,27 @@ Test Email
Text to display in the tip input Text to display in the tip input
Text to display on buttons allowing the user to enter a custom amount Text to display on buttons allowing the user to enter a custom amount
Text to display on each button for items with a specific price Text to display on each button for items with a specific price
Theme
Tip percentage amounts (comma separated) Tip percentage amounts (comma separated)
Translations
Two-Factor Authentication
Unarchive this store
Unify on-chain and lightning payment URL/QR code Unify on-chain and lightning payment URL/QR code
Update Password
Update Webhook
Upload PSBT from file Upload PSBT from file
Url of the Dynamic DNS service you are using Url of the Dynamic DNS service you are using
Use custom theme Use custom theme
Use SSL Use SSL
User can input custom amount User can input custom amount
User can input discount in % User can input discount in %
Users
UTXOs to spend from UTXOs to spend from
Verification Code Verification Code
Wallet file Wallet file
Wallet file content Wallet file content
Wallets
Webhooks
Welcome to {0} Welcome to {0}
Your dynamic DNS hostname Your dynamic DNS hostname
"""; """;

View File

@@ -10,6 +10,9 @@ using BTCPayServer.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Newtonsoft.Json.Linq;
using static System.Net.Mime.MediaTypeNames;
using YamlDotNet.Core.Tokens;
namespace BTCPayServer.Services namespace BTCPayServer.Services
{ {
@@ -34,6 +37,22 @@ namespace BTCPayServer.Services
return false; return false;
} }
} }
public static Translations CreateFromJson(string text)
{
text = (text ?? "{}");
var translations = new List<(string key, string? value)>();
foreach (var prop in JObject.Parse(text).Properties())
{
var v = prop.Value.Value<string>();
if (string.IsNullOrEmpty(v))
translations.Add((prop.Name, prop.Name));
else
translations.Add((prop.Name, v));
}
return new Translations(translations
.Select(t => KeyValuePair.Create(t.key, t.value)));
}
public static Translations CreateFromText(string text) public static Translations CreateFromText(string text)
{ {
text = (text ?? "").Replace("\r\n", "\n"); text = (text ?? "").Replace("\r\n", "\n");
@@ -116,7 +135,15 @@ namespace BTCPayServer.Services
{ {
return GetEnumerator(); return GetEnumerator();
} }
public string ToJsonFormat()
{
JObject obj = new JObject();
foreach (var record in Records)
{
obj.Add(record.Key, record.Value);
}
return obj.ToString(Newtonsoft.Json.Formatting.Indented);
}
public string ToTextFormat() public string ToTextFormat()
{ {
return string.Join('\n', Records.OrderBy(r => r.Key).Select(r => $"{r.Key} => {r.Value}").ToArray()); return string.Join('\n', Records.OrderBy(r => r.Key).Select(r => $"{r.Key} => {r.Value}").ToArray());

View File

@@ -1,9 +1,11 @@
using System.Globalization; using System.Globalization;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using AngleSharp.Html;
using BTCPayServer.Abstractions.Services; using BTCPayServer.Abstractions.Services;
using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Localization; using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -12,6 +14,8 @@ namespace BTCPayServer.TagHelpers
{ {
[HtmlTargetElement(Attributes = "text-translate")] [HtmlTargetElement(Attributes = "text-translate")]
[HtmlTargetElement(Attributes = "html-translate")] [HtmlTargetElement(Attributes = "html-translate")]
[HtmlTargetElement("input", Attributes = "[type=submit]")]
[HtmlTargetElement(Attributes = "[id=page-primary]")]
public class TranslateTagHelper : TagHelper public class TranslateTagHelper : TagHelper
{ {
private readonly IStringLocalizer<TranslateTagHelper> _localizer; private readonly IStringLocalizer<TranslateTagHelper> _localizer;
@@ -19,6 +23,7 @@ namespace BTCPayServer.TagHelpers
public bool TextTranslate { get; set; } public bool TextTranslate { get; set; }
public bool HtmlTranslate { get; set; } public bool HtmlTranslate { get; set; }
public string Value { get; set; }
public TranslateTagHelper( public TranslateTagHelper(
@@ -41,15 +46,26 @@ namespace BTCPayServer.TagHelpers
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{ {
var originalContent = output.Content.IsModified if (Value != null)
? output.Content.GetContent() {
: (await output.GetChildContentAsync()).GetContent(); output.CopyHtmlAttribute("value", context);
}
var newContent = _localizer[originalContent]; if (context.TagName == "input")
if (TextTranslate) {
output.Content.SetContent(newContent); var newContent = _localizer[Value];
output.Attributes.SetAttribute("value", newContent.Value);
}
else else
output.Content.SetHtmlContent(_safe.Raw(newContent.Value)); {
var originalContent = output.Content.IsModified
? output.Content.GetContent()
: (await output.GetChildContentAsync()).GetContent();
var newContent = _localizer[originalContent.Trim()];
if (HtmlTranslate)
output.Content.SetHtmlContent(_safe.Raw(newContent.Value));
else
output.Content.SetContent(newContent);
}
} }
} }
} }

View File

@@ -30,7 +30,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button> <button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
</div> </div>

View File

@@ -16,7 +16,7 @@
<li class="nav-item" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item" permission="@Policies.CanModifyStoreSettings">
<a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")"> <a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")">
<vc:icon symbol="nav-crowdfund" /> <vc:icon symbol="nav-crowdfund" />
<span>@appType.Description</span> <span text-translate="true">Crowdfund</span>
</a> </a>
</li> </li>
@if (apps.Any()) @if (apps.Any())
@@ -24,7 +24,7 @@
<li class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings"> <li class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings">
<span class="nav-link"> <span class="nav-link">
<vc:icon symbol="nav-crowdfund" /> <vc:icon symbol="nav-crowdfund" />
<span>@appType.Description</span> <span>Crowdfund</span>
</span> </span>
</li> </li>
} }

View File

@@ -27,7 +27,7 @@
<form method="post" permissioned="@Policies.CanModifyStoreSettings"> <form method="post" permissioned="@Policies.CanModifyStoreSettings">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<div> <div>
<button id="page-primary" type="submit" class="btn btn-primary order-sm-1">Save</button> <button id="page-primary" type="submit" class="btn btn-primary order-sm-1">Save</button>
@if (Model.Archived) @if (Model.Archived)

View File

@@ -25,7 +25,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<a id="page-primary" class="btn btn-primary" role="button" asp-controller="@controller" asp-action="CreateOrEditRole" asp-route-role="create" asp-route-storeId="@storeId" permission="@permission">Add Role</a> <a id="page-primary" class="btn btn-primary" role="button" asp-controller="@controller" asp-action="CreateOrEditRole" asp-route-role="create" asp-route-storeId="@storeId" permission="@permission">Add Role</a>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -4,7 +4,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -8,7 +8,7 @@
<li class="nav-item" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item" permission="@Policies.CanModifyStoreSettings">
<a asp-area="" asp-controller="UIPayButton" asp-action="PayButton" asp-route-storeId="@store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PayButton)" id="StoreNav-PayButton"> <a asp-area="" asp-controller="UIPayButton" asp-action="PayButton" asp-route-storeId="@store.Id" class="nav-link @ViewData.ActivePageClass(StoreNavPages.PayButton)" id="StoreNav-PayButton">
<vc:icon symbol="nav-pay-button"/> <vc:icon symbol="nav-pay-button"/>
<span>Pay Button</span> <span text-translate="true">Pay Button</span>
</a> </a>
</li> </li>
} }

View File

@@ -175,7 +175,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -16,7 +16,7 @@
<li class="nav-item" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item" permission="@Policies.CanModifyStoreSettings">
<a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")"> <a asp-area="" asp-controller="UIApps" asp-action="CreateApp" asp-route-storeId="@store.Id" asp-route-appType="@appType.Type" class="nav-link @ViewData.ActivePageClass(AppsNavPages.Create, appType.Type)" id="@($"StoreNav-Create{appType.Type}")">
<vc:icon symbol="nav-pointofsale" /> <vc:icon symbol="nav-pointofsale" />
<span>@appType.Description</span> <span text-translate="true">Point of Sale</span>
</a> </a>
</li> </li>
@if (apps.Any()) @if (apps.Any())
@@ -24,7 +24,7 @@
<li class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings"> <li class="nav-item" not-permission="@Policies.CanModifyStoreSettings" permission="@Policies.CanViewStoreSettings">
<span class="nav-link"> <span class="nav-link">
<vc:icon symbol="nav-pointofsale" /> <vc:icon symbol="nav-pointofsale" />
<span>@appType.Description</span> <span>Point of Sale</span>
</span> </span>
</li> </li>
} }

View File

@@ -35,7 +35,7 @@
<form method="post" permissioned="@Policies.CanModifyStoreSettings"> <form method="post" permissioned="@Policies.CanModifyStoreSettings">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<div> <div>
<button id="page-primary" type="submit" class="btn btn-primary order-sm-1">Save</button> <button id="page-primary" type="submit" class="btn btn-primary order-sm-1">Save</button>
@if (Model.Archived) @if (Model.Archived)

View File

@@ -10,7 +10,7 @@
<li class="nav-item" permission="@Policies.CanModifyStoreSettings"> <li class="nav-item" permission="@Policies.CanModifyStoreSettings">
<a asp-area="" asp-controller="UIShopify" asp-action="EditShopify" asp-route-storeId="@store.Id" class="nav-link @ViewData.ActivePageClass("shopify", nameof(StoreNavPages))" id="StoreNav-Shopify"> <a asp-area="" asp-controller="UIShopify" asp-action="EditShopify" asp-route-storeId="@store.Id" class="nav-link @ViewData.ActivePageClass("shopify", nameof(StoreNavPages))" id="StoreNav-Shopify">
<vc:icon symbol="logo-shopify" /> <vc:icon symbol="logo-shopify" />
<span>Shopify</span> <span text-translate="true">Shopify</span>
</a> </a>
</li> </li>
} }

View File

@@ -8,4 +8,4 @@
} }
} }
<partial name="_Form" model="@Model.Form" /> <partial name="_Form" model="@Model.Form" />
<input id="page-primary" type="submit" class="btn btn-primary" name="command" value="Submit" /> <input id="page-primary" type="submit" class="btn btn-primary" value="Submit" />

View File

@@ -2,7 +2,7 @@
ViewData["Title"] = "Signed out"; ViewData["Title"] = "Signed out";
} }
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<p> <p>
You have successfully signed out. You have successfully signed out.
</p> </p>

View File

@@ -9,7 +9,7 @@
<form asp-action="CreateApp" asp-route-appType="@Model.AppType"> <form asp-action="CreateApp" asp-route-appType="@Model.AppType">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<input id="page-primary" type="submit" value="Create" class="btn btn-primary" /> <input id="page-primary" type="submit" value="Create" class="btn btn-primary" />
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -11,7 +11,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">Register Device</li> <li class="breadcrumb-item active" aria-current="page">Register Device</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -36,7 +36,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<input id="page-primary" type="submit" value="Create" class="btn btn-primary" /> <input id="page-primary" type="submit" value="Create" class="btn btn-primary" />
</div> </div>

View File

@@ -177,7 +177,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">Invoice</li> <li class="breadcrumb-item active" aria-current="page">Invoice</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<div> <div>
@if (Model.ShowCheckout) @if (Model.ShowCheckout)

View File

@@ -26,7 +26,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<a id="page-primary" data-bs-toggle="collapse" data-bs-target="#AddAddress" class="btn btn-primary" role="button"> <a id="page-primary" data-bs-toggle="collapse" data-bs-target="#AddAddress" class="btn btn-primary" role="button">
Add Address Add Address
</a> </a>

View File

@@ -9,7 +9,7 @@
}; };
} }
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<p>Scan the QR code with your Lightning wallet to link it to your user account.</p> <p>Scan the QR code with your Lightning wallet to link it to your user account.</p>

View File

@@ -16,7 +16,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" name="command" type="submit" class="btn btn-primary" value="Save">Save</button> <button id="page-primary" name="command" type="submit" class="btn btn-primary" value="Save">Save</button>
</div> </div>

View File

@@ -5,7 +5,7 @@
var cryptoCode = Context.GetRouteValue("cryptoCode"); var cryptoCode = Context.GetRouteValue("cryptoCode");
} }
<h2 class="mt-1 mb-2">@ViewData["Title"]</h2> <h2 class="mt-1 mb-2" text-translate="true">@ViewData["Title"]</h2>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">

View File

@@ -5,7 +5,7 @@
ViewData["Title"] = "Lightning Payout Result"; ViewData["Title"] = "Lightning Payout Result";
} }
<h2 class="mt-1 mb-4">@ViewData["Title"]</h2> <h2 class="mt-1 mb-4" text-translate="true">@ViewData["Title"]</h2>
@foreach (var item in Model) @foreach (var item in Model)
{ {
<div class="alert alert-@(item.Result == PayResult.Ok ? "success" : "danger") mb-3" role="alert"> <div class="alert alert-@(item.Result == PayResult.Ok ? "success" : "danger") mb-3" role="alert">

View File

@@ -8,7 +8,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<a id="page-primary" class="btn btn-primary" asp-action="AddApiKey"> <a id="page-primary" class="btn btn-primary" asp-action="AddApiKey">
Generate Key Generate Key
</a> </a>

View File

@@ -34,7 +34,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" type="submit" class="btn btn-primary">Generate API Key</button> <button id="page-primary" type="submit" class="btn btn-primary">Generate API Key</button>
</div> </div>

View File

@@ -5,7 +5,7 @@
<form method="post"> <form method="post">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary">Update Password</button> <button id="page-primary" type="submit" class="btn btn-primary">Update Password</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -10,7 +10,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -1,9 +1,9 @@
@model GenerateRecoveryCodesViewModel @model GenerateRecoveryCodesViewModel
@{ @{
ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, "Recovery codes"); ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, "Recovery codes");
} }
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<div class="alert alert-warning" role="alert"> <div class="alert alert-warning" role="alert">

View File

@@ -10,7 +10,7 @@
<form method="post" enctype="multipart/form-data"> <form method="post" enctype="multipart/form-data">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary">Save</button> <button id="page-primary" type="submit" class="btn btn-primary">Save</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -4,7 +4,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<a id="page-primary" class="btn btn-primary" asp-action="LoginCodes">Regenerate code</a> <a id="page-primary" class="btn btn-primary" asp-action="LoginCodes">Regenerate code</a>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -12,7 +12,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="update">Save</button> <button id="page-primary" type="submit" class="btn btn-primary" name="command" value="update">Save</button>
</div> </div>

View File

@@ -5,7 +5,7 @@
<form method="post"> <form method="post">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary">Set Password</button> <button id="page-primary" type="submit" class="btn btn-primary">Set Password</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -4,7 +4,7 @@
ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, "Two-Factor Authentication"); ViewData.SetActivePage(ManageNavPages.TwoFactorAuthentication, "Two-Factor Authentication");
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<div class="row"> <div class="row">

View File

@@ -32,7 +32,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
<a id="NotificationSettings" asp-controller="UIManage" asp-action="NotificationSettings" class="btn btn-secondary d-flex align-items-center"> <a id="NotificationSettings" asp-controller="UIManage" asp-action="NotificationSettings" class="btn btn-secondary d-flex align-items-center">
<vc:icon symbol="nav-store-settings" /> <vc:icon symbol="nav-store-settings" />
</a> </a>

View File

@@ -17,7 +17,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" name="command" type="submit" class="btn btn-primary" value="Save">Save</button> <button id="page-primary" name="command" type="submit" class="btn btn-primary" value="Save">Save</button>
</div> </div>

View File

@@ -30,7 +30,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<div> <div>
@if (string.IsNullOrEmpty(Model.Id)) @if (string.IsNullOrEmpty(Model.Id))

View File

@@ -8,7 +8,7 @@
ViewData.SetActivePage(StoreNavPages.PayoutProcessors, "Payout Processors", storeId); ViewData.SetActivePage(StoreNavPages.PayoutProcessors, "Payout Processors", storeId);
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
</div> </div>
<p>Payout Processors allow BTCPay Server to handle payouts in an automated way.</p> <p>Payout Processors allow BTCPay Server to handle payouts in an automated way.</p>

View File

@@ -23,7 +23,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<div> <div>
@if (string.IsNullOrEmpty(Model.Id)) @if (string.IsNullOrEmpty(Model.Id))

View File

@@ -15,7 +15,7 @@
<form method="post" enctype="multipart/form-data"> <form method="post" enctype="multipart/form-data">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button> <button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
@@ -64,8 +64,8 @@
<div class="form-text">In order to upload a logo, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</div> <div class="form-text">In order to upload a logo, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</div>
} }
</div> </div>
<h3 class="mt-5 mb-3">Theme</h3> <h3 class="mt-5 mb-3" text-translate="true">Theme</h3>
<p>Use the default Light or Dark Themes, or provide a custom CSS theme file below.</p> <p>Use the default Light or Dark Themes, or provide a custom CSS theme file below.</p>
<div class="d-flex align-items-center mb-3"> <div class="d-flex align-items-center mb-3">

View File

@@ -11,7 +11,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -12,7 +12,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -14,7 +14,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<input id="page-primary" type="submit" value="Create" class="btn btn-primary" /> <input id="page-primary" type="submit" value="Create" class="btn btn-primary" />
</div> </div>

View File

@@ -6,7 +6,7 @@
<form method="post"> <form method="post">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Generate">Generate</button> <button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Generate">Generate</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -12,7 +12,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Create Account</button> <button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Create Account</button>
</div> </div>

View File

@@ -14,7 +14,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">Provider</li> <li class="breadcrumb-item active" aria-current="page">Provider</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -14,7 +14,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">Provider</li> <li class="breadcrumb-item active" aria-current="page">Provider</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -14,9 +14,12 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button> <div>
<button cheat-mode="true" class="btn btn-outline-info" name="command" value="Fake">Fill fake</button>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
</div>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -14,7 +14,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">Provider</li> <li class="breadcrumb-item active" aria-current="page">Provider</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -14,7 +14,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">Provider</li> <li class="breadcrumb-item active" aria-current="page">Provider</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -5,7 +5,7 @@
<form method="post" autocomplete="off"> <form method="post" autocomplete="off">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button> <button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -4,7 +4,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
<a asp-action="storage" asp-route-forceChoice="true" asp-route-returnurl="@ViewData["ReturnUrl"]" class="btn btn-secondary d-flex align-items-center"> <a asp-action="storage" asp-route-forceChoice="true" asp-route-returnurl="@ViewData["ReturnUrl"]" class="btn btn-secondary d-flex align-items-center">
<vc:icon symbol="settings" /> <vc:icon symbol="settings" />
</a> </a>

View File

@@ -11,7 +11,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -11,7 +11,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -6,7 +6,7 @@
} }
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<a id="page-primary" asp-action="CreateDictionary" class="btn btn-primary" role="button"> <a id="page-primary" asp-action="CreateDictionary" class="btn btn-primary" role="button">
Create Create
</a> </a>

View File

@@ -1,10 +1,10 @@
@model BTCPayServer.Models.StoreViewModels.ListStoresViewModel @model BTCPayServer.Models.StoreViewModels.ListStoresViewModel
@{ @{
Layout = "_Layout"; Layout = "_Layout";
ViewData.SetActivePage(ServerNavPages.Stores, "Store Overview"); ViewData.SetActivePage(ServerNavPages.Stores, "Store Overview");
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -14,7 +14,7 @@
const string sortByAsc = "Sort by email ascending..."; const string sortByAsc = "Sort by email ascending...";
} }
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<a id="page-primary" asp-action="CreateUser" class="btn btn-primary" role="button"> <a id="page-primary" asp-action="CreateUser" class="btn btn-primary" role="button">
Add User Add User
</a> </a>

View File

@@ -12,7 +12,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -11,7 +11,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -1,10 +1,10 @@
@model BTCPayServer.Models.ServerViewModels.LogsViewModel @model BTCPayServer.Models.ServerViewModels.LogsViewModel
@{ @{
ViewData.SetActivePage(ServerNavPages.Logs, "Logs"); ViewData.SetActivePage(ServerNavPages.Logs, "Logs");
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -1,10 +1,10 @@
@model BTCPayServer.Models.ServerViewModels.MaintenanceViewModel @model BTCPayServer.Models.ServerViewModels.MaintenanceViewModel
@{ @{
ViewData.SetActivePage(ServerNavPages.Maintenance, "Maintenance"); ViewData.SetActivePage(ServerNavPages.Maintenance, "Maintenance");
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -11,7 +11,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -20,7 +20,7 @@
<form method="post"> <form method="post">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button> <button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Save</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -11,7 +11,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -12,7 +12,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -1,10 +1,10 @@
@model BTCPayServer.Models.ServerViewModels.ServicesViewModel @model BTCPayServer.Models.ServerViewModels.ServicesViewModel
@{ @{
ViewData.SetActivePage(ServerNavPages.Services, "Services"); ViewData.SetActivePage(ServerNavPages.Services, "Services");
} }
<div class="sticky-header"> <div class="sticky-header">
<h2 class="my-1">@ViewData["Title"]</h2> <h2 class="my-1" text-translate="true">@ViewData["Title"]</h2>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -12,7 +12,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Next</button> <button id="page-primary" type="submit" class="btn btn-primary" name="command" value="Save">Next</button>
</div> </div>

View File

@@ -16,7 +16,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">User</li> <li class="breadcrumb-item active" aria-current="page">User</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<button id="page-primary" name="command" type="submit" class="btn btn-primary" value="Save">Save</button> <button id="page-primary" name="command" type="submit" class="btn btn-primary" value="Save">Save</button>
</div> </div>

View File

@@ -24,7 +24,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<input id="page-primary" type="submit" value="Create" class="btn btn-primary"/> <input id="page-primary" type="submit" value="Create" class="btn btn-primary"/>
</div> </div>

View File

@@ -34,7 +34,7 @@
<vc:icon symbol="info" /> <vc:icon symbol="info" />
</a> </a>
</h2> </h2>
<a permission="@Policies.CanCreateNonApprovedPullPayments" asp-action="NewPullPayment" asp-route-storeId="@storeId" class="btn btn-primary" role="button" id="NewPullPayment"> <a id="page-primary" permission="@Policies.CanCreateNonApprovedPullPayments" asp-action="NewPullPayment" asp-route-storeId="@storeId" class="btn btn-primary" role="button">
Create Pull Payment Create Pull Payment
</a> </a>
</div> </div>

View File

@@ -59,7 +59,7 @@
<form method="post" enctype="multipart/form-data" permissioned="@Policies.CanModifyStoreSettings"> <form method="post" enctype="multipart/form-data" permissioned="@Policies.CanModifyStoreSettings">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary">Save</button> <button id="page-primary" type="submit" class="btn btn-primary">Save</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -17,12 +17,12 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
} }
else else
{ {
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
} }
<input id="page-primary" type="submit" value="Request Pairing" class="btn btn-primary" /> <input id="page-primary" type="submit" value="Request Pairing" class="btn btn-primary" />
</div> </div>

View File

@@ -14,7 +14,7 @@
var store = ViewContext.HttpContext.GetStoreData(); var store = ViewContext.HttpContext.GetStoreData();
} }
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
@if (Model.IsSetUp) @if (Model.IsSetUp)

View File

@@ -11,7 +11,7 @@
} }
<form method="post" enctype="multipart/form-data" permissioned="@Policies.CanModifyStoreSettings"> <form method="post" enctype="multipart/form-data" permissioned="@Policies.CanModifyStoreSettings">
<div class="sticky-header"> <div class="sticky-header">
<h2>Store Settings</h2> <h2 text-translate="true">Store Settings</h2>
<button id="page-primary" type="submit" class="btn btn-primary">Save</button> <button id="page-primary" type="submit" class="btn btn-primary">Save</button>
</div> </div>
@@ -38,7 +38,7 @@
<span asp-validation-for="StoreWebsite" class="text-danger"></span> <span asp-validation-for="StoreWebsite" class="text-danger"></span>
</div> </div>
<h3 class="mt-5 mb-3">Branding</h3> <h3 class="mt-5 mb-3" text-translate="true">Branding</h3>
<div class="form-group"> <div class="form-group">
<label asp-for="BrandColor" class="form-label"></label> <label asp-for="BrandColor" class="form-label"></label>
<div class="input-group"> <div class="input-group">
@@ -104,8 +104,8 @@
<div class="form-text">In order to upload a CSS file, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</div> <div class="form-text">In order to upload a CSS file, a <a asp-controller="UIServer" asp-action="Files">file storage</a> must be configured.</div>
} }
</div> </div>
<h3 class="mt-5 mb-3">Payment</h3> <h3 class="mt-5 mb-3" text-translate="true">Payment</h3>
<div class="form-group"> <div class="form-group">
<label asp-for="DefaultCurrency" class="form-label"></label> <label asp-for="DefaultCurrency" class="form-label"></label>
<input asp-for="DefaultCurrency" class="form-control w-auto" currency-selection /> <input asp-for="DefaultCurrency" class="form-control w-auto" currency-selection />
@@ -167,21 +167,21 @@
</form> </form>
<div permission="@Policies.CanModifyStoreSettings"> <div permission="@Policies.CanModifyStoreSettings">
<h3 class="mt-5 mb-3">Additional Actions</h3> <h3 class="mt-5 mb-3" text-translate="true">Additional Actions</h3>
<div id="danger-zone" class="d-flex flex-wrap align-items-center gap-3 mb-5 mt-2"> <div id="danger-zone" class="d-flex flex-wrap align-items-center gap-3 mb-5 mt-2">
<form asp-action="ToggleArchive" asp-route-storeId="@Model.Id" method="post"> <form asp-action="ToggleArchive" asp-route-storeId="@Model.Id" method="post">
<button type="submit" class="btn btn-outline-secondary" id="btn-archive-toggle"> <button type="submit" class="btn btn-outline-secondary" id="btn-archive-toggle">
@if (Model.Archived) @if (Model.Archived)
{ {
<span class="text-nowrap" data-bs-toggle="tooltip" title="Unarchive this store">Unarchive this store</span> <span class="text-nowrap" data-bs-toggle="tooltip" title="Unarchive this store" text-translate="true">Unarchive this store</span>
} }
else else
{ {
<span class="text-nowrap" data-bs-toggle="tooltip" title="Archive this store so that it does not appear in the stores list by default">Archive this store</span> <span class="text-nowrap" data-bs-toggle="tooltip" title="Archive this store so that it does not appear in the stores list by default" text-translate="true">Archive this store</span>
} }
</button> </button>
</form> </form>
<a id="DeleteStore" class="btn btn-outline-danger" asp-action="DeleteStore" asp-route-storeId="@Model.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The store <strong>@Html.Encode(Model.StoreName)</strong> will be permanently deleted. This action will also delete all invoices, apps and data associated with the store." data-confirm-input="DELETE">Delete this store</a> <a id="DeleteStore" class="btn btn-outline-danger" asp-action="DeleteStore" asp-route-storeId="@Model.Id" data-bs-toggle="modal" data-bs-target="#ConfirmModal" data-description="The store <strong>@Html.Encode(Model.StoreName)</strong> will be permanently deleted. This action will also delete all invoices, apps and data associated with the store." data-confirm-input="DELETE" text-translate="true">Delete this store</a>
</div> </div>
</div> </div>

View File

@@ -7,7 +7,7 @@
ViewData.SetActivePage(StoreNavPages.Lightning, $"{Model.CryptoCode} Lightning", $"{Context.GetStoreData().Id}-{Model.CryptoCode}"); ViewData.SetActivePage(StoreNavPages.Lightning, $"{Model.CryptoCode} Lightning", $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
} }
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<div class="mb-5"> <div class="mb-5">
<div class="mb-3"> <div class="mb-3">

View File

@@ -8,7 +8,7 @@
<form method="post"> <form method="post">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" name="command" type="submit" value="save" class="btn btn-primary">Save</button> <button id="page-primary" name="command" type="submit" value="save" class="btn btn-primary">Save</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -22,7 +22,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
@if (Model.IsNew) @if (Model.IsNew)
{ {

View File

@@ -9,7 +9,7 @@
<form method="post" permissioned="@Policies.CanModifyStoreSettings"> <form method="post" permissioned="@Policies.CanModifyStoreSettings">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" name="command" type="submit" class="btn btn-primary" value="Save">Save</button> <button id="page-primary" name="command" type="submit" class="btn btn-primary" value="Save">Save</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -30,12 +30,12 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
} }
else else
{ {
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
} }
<button id="page-primary" type="submit" class="btn btn-primary mt-3" title="Approve this pairing demand">Approve</button> <button id="page-primary" type="submit" class="btn btn-primary mt-3" title="Approve this pairing demand">Approve</button>
</div> </div>

View File

@@ -23,7 +23,7 @@
</li> </li>
<li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li> <li class="breadcrumb-item active" aria-current="page">@ViewData["Title"]</li>
</ol> </ol>
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
</nav> </nav>
<div permission="@Policies.CanModifyStoreSettings"> <div permission="@Policies.CanModifyStoreSettings">
@if (Model.Rules.Any()) @if (Model.Rules.Any())

View File

@@ -19,7 +19,7 @@
} }
</style> </style>
} }
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<div class="row"> <div class="row">
<div class="col-xxl-constrain col-xl-8"> <div class="col-xxl-constrain col-xl-8">

View File

@@ -6,7 +6,7 @@
} }
<form method="post"> <form method="post">
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<button id="page-primary" type="submit" class="btn btn-primary mt-3">Send test webhook</button> <button id="page-primary" type="submit" class="btn btn-primary mt-3">Send test webhook</button>
</div> </div>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />

View File

@@ -16,7 +16,7 @@
<script src="~/vendor/vue-qrcode-reader/VueQrcodeReader.umd.min.js" asp-append-version="true"></script> <script src="~/vendor/vue-qrcode-reader/VueQrcodeReader.umd.min.js" asp-append-version="true"></script>
<link href="~/vendor/vue-qrcode-reader/vue-qrcode-reader.css" rel="stylesheet" asp-append-version="true"/> <link href="~/vendor/vue-qrcode-reader/vue-qrcode-reader.css" rel="stylesheet" asp-append-version="true"/>
} }
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<div class="row"> <div class="row">
<div class="col-xl-8 col-xxl-constrain"> <div class="col-xl-8 col-xxl-constrain">

View File

@@ -8,7 +8,7 @@
<div class="sticky-header"> <div class="sticky-header">
<h2>@ViewData["Title"]</h2> <h2 text-translate="true">@ViewData["Title"]</h2>
<a id="page-primary" asp-action="NewWebhook" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")" permission="@Policies.CanModifyStoreSettings"> <a id="page-primary" asp-action="NewWebhook" class="btn btn-primary" role="button" asp-route-storeId="@Context.GetRouteValue("storeId")" permission="@Policies.CanModifyStoreSettings">
Create Webhook Create Webhook
</a> </a>

View File

@@ -52,7 +52,7 @@
} }
else else
{ {
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
<div class="row"> <div class="row">
<div class="col-xl-8 col-xxl-constrain"> <div class="col-xl-8 col-xxl-constrain">

View File

@@ -1,10 +1,10 @@
@using BTCPayServer.Client @using BTCPayServer.Client
@model BTCPayServer.Models.StoreViewModels.ListStoresViewModel @model BTCPayServer.Models.StoreViewModels.ListStoresViewModel
@{ @{
ViewData.SetActivePage(StoreNavPages.Index, Model.Archived ? "Archived Stores" : "Stores"); ViewData.SetActivePage(StoreNavPages.Index, Model.Archived ? "Archived Stores" : "Stores");
} }
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
@if (Model.Stores.Any()) @if (Model.Stores.Any())
{ {

View File

@@ -22,6 +22,6 @@
<span asp-validation-for="PreferredExchange" class="text-danger"></span> <span asp-validation-for="PreferredExchange" class="text-danger"></span>
</div> </div>
<div class="form-group mt-4"> <div class="form-group mt-4">
<input type="submit" value="Create Store" class="btn btn-primary" id="Create" /> <input type="submit" value="Create Store" class="btn btn-primary" id="Create" />
</div> </div>
</form> </form>

View File

@@ -1,4 +1,4 @@
@using BTCPayServer.Abstractions.Models @using BTCPayServer.Abstractions.Models
@model WalletLabelsModel @model WalletLabelsModel
@{ @{
var walletId = Context.GetRouteValue("walletId").ToString(); var walletId = Context.GetRouteValue("walletId").ToString();
@@ -11,7 +11,7 @@
</script> </script>
} }
<h2 class="mb-2 mb-lg-3">@ViewData["Title"]</h2> <h2 class="mb-2 mb-lg-3" text-translate="true">@ViewData["Title"]</h2>
<partial name="_StatusMessage" /> <partial name="_StatusMessage" />
@if (Model.Labels.Any()) @if (Model.Labels.Any())