Add translation for store rate and wallet setup (#6271)

This commit is contained in:
Nicolas Dorier 2024-10-03 19:21:19 +09:00 committed by GitHub
parent a698aa8a5b
commit 413a9b4269
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 474 additions and 400 deletions

View file

@ -1,3 +1,5 @@
Password => Cyphercode
Email address => Cypher ID
Welcome to {0} => Yo at {0}
{
"Password" : "Cyphercode",
"Email address" : "Cypher ID",
"Welcome to {0}" : "Yo at {0}"
}

View file

@ -352,7 +352,7 @@ retry:
}
// Go through all cshtml file, search for text-translate or ViewLocalizer usage
using (var tester = CreateServerTester())
using (var tester = CreateServerTester(newDb: true))
{
await tester.StartAsync();
var engine = tester.PayTester.GetService<RazorProjectEngine>();
@ -360,14 +360,17 @@ retry:
{
var filePath = file.FullName;
var txt = File.ReadAllText(file.FullName);
if (txt.Contains("ViewLocalizer"))
foreach (string localizer in new[] { "ViewLocalizer", "StringLocalizer" })
{
var matches = Regex.Matches(txt, "ViewLocalizer\\[\"(.*?)\"[\\],]");
if (txt.Contains(localizer))
{
var matches = Regex.Matches(txt, localizer + "\\[\"(.*?)\"[\\],]");
foreach (Match match in matches)
{
defaultTranslatedKeys.Add(match.Groups[1].Value);
}
}
}
filePath = filePath.Replace(Path.Combine(soldir.FullName, "BTCPayServer"), "/");
var item = engine.FileSystem.GetItem(filePath);
@ -379,12 +382,18 @@ retry:
}
defaultTranslatedKeys = defaultTranslatedKeys.Select(d => d.Trim()).Distinct().OrderBy(o => o).ToList();
JObject obj = new JObject();
foreach (var v in defaultTranslatedKeys)
{
obj.Add(v, "");
}
var path = Path.Combine(soldir.FullName, "BTCPayServer/Services/Translations.Default.cs");
var defaultTranslation = File.ReadAllText(path);
var startIdx = defaultTranslation.IndexOf("\"\"\"");
var endIdx = defaultTranslation.LastIndexOf("\"\"\"");
var content = defaultTranslation.Substring(0, startIdx + 3);
content += "\n" + String.Join('\n', defaultTranslatedKeys) + "\n";
content += "\n" + obj.ToString(Formatting.Indented) + "\n";
content += defaultTranslation.Substring(endIdx);
File.WriteAllText(path, content);
}

View file

@ -89,6 +89,7 @@ namespace BTCPayServer.Hosting
services.TryAddSingleton<IHtmlLocalizerFactory, LocalizerFactory>();
services.TryAddSingleton<LocalizerService>();
services.TryAddSingleton<ViewLocalizer>();
services.TryAddSingleton<IStringLocalizer>(o => o.GetRequiredService<IStringLocalizerFactory>().Create("",""));
services.AddSingleton<MvcNewtonsoftJsonOptions>(o => o.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value);
services.AddSingleton<JsonSerializerSettings>(o => o.GetRequiredService<IOptions<MvcNewtonsoftJsonOptions>>().Value.SerializerSettings);

View file

@ -64,7 +64,7 @@ namespace BTCPayServer.Hosting
continue;
}
var savedHash = dictionary.Metadata.ToObject<DictionaryFileMetadata>().Hash;
var translations = Translations.CreateFromText(File.ReadAllText(file));
var translations = Translations.CreateFromJson(File.ReadAllText(file));
var currentHash = new uint256(SHA256.HashData(Encoding.UTF8.GetBytes(translations.ToJsonFormat())));
if (savedHash != currentHash)

View file

@ -11,307 +11,377 @@ namespace BTCPayServer.Services
// Please run it before release.
var knownTranslations =
"""
Access Tokens
Account
Account key
Account key path
Add additional fee (network fee) to invoice
Add Address
Add Exchange Rate Spread
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 must approve new users
Administrator
Allow anyone to create invoice
Allow form for public use
Allow payee to create invoices with custom amounts
Allow payee to pass a comment
Allow Stores use the Server's SMTP email settings as their default
Always include non-witness UTXO if available
Amazon S3
Amount
API Key
API Keys
App
App Name
App Type
Application
Approve
Archive this store
Authenticator code
Auto-detect language on checkout
Automatically approve claims
Available Payment Methods
Azure Blob Storage
Backend's language
Batch size
BIP39 Seed (12/24 word mnemonic phrase) or HD private key (xprv...)
Brand Color
Branding
Buyer Email
Callback Notification URL
Can use hot wallet
Can use RPC import
Celebrate payment with confetti
Check releases on GitHub and notify when new BTCPay Server version is available
Checkout Appearance
Clone
Colors to rotate between with animation when a payment is made. One color per line.
Confirm new password
Confirm password
Connection string
Consider the invoice paid even if the paid amount is % less than expected
Consider the invoice settled when the payment transaction
Contact URL
Contact Us
Contribution Perks Template
Count all invoices created on the store as part of the goal
Create
Create a new app
Create a new dictionary
Create Account
Create Form
Create Invoice
Create Pull Payment
Create Request
Create Store
Create Webhook
Create your account
Crowdfund
Currency
Current password
Custom CSS
Custom HTML title to display on Checkout page
Custom sound file for successful payment
Custom Theme Extension Type
Custom Theme File
Dashboard
Default currency
Default language on checkout
Default payment method on checkout
Default role for users on a new store
Delete this store
Derivation scheme
Derivation scheme format
Description
Description template of the lightning invoice
Destination Address
Dictionaries
Dictionaries enable you to translate the BTCPay Server backend into different languages.
Dictionary
Disable public user registration
Disable stores from using the server's email settings as backup
Discourage search engines from indexing this site
Display app on website root
Display contribution ranking
Display contribution value
Display item selection for keypad
Display Lightning payment amounts in Satoshis
Display the category list
Display the search bar
Display Title
Disqus Shortname
Do not allow additional contributions after target has been reached
Does not extend a BTCPay Server theme, fully custom
Domain
Domain name
Don't create UTXO change
Email
Email address
Email confirmation required
Email confirmed?
Emails
Enable background animations on new payments
Enable Disqus Comments
Enable experimental features
Enable LNURL
Enable Payjoin/P2EP
Enable public receipt page for settled invoices
Enable public user registration
Enable sounds on checkout page
Enable sounds on new payments
Enable tips
End date
Error
Expiration Date
Export
Extends the BTCPay Server Dark theme
Extends the BTCPay Server Light theme
Fallback
Featured Image URL
Fee rate (sat/vB)
Files
Forgot password?
Form configuration (JSON)
Forms
Gap limit
Generate
Generate API Key
Generate Key
Google Cloud Storage
GRPC SSL Cipher suite (GRPC_SSL_CIPHER_SUITES)
Hide Sensitive Info
If a translation isnt available in the new dictionary, it will be searched in the fallback.
Image
Invoice currency
Invoice expires if the full amount has not been paid after
Invoice metadata
Invoices
Is administrator?
Is signing key
Item Description
Keypad
Lightning node (LNURL Auth)
LNURL Classic Mode
Local File System
Log in
Login Codes
Logo
Logout
Logs
Maintenance
Make Crowdfund Public
Manage Account
Manage Plugins
Master fingerprint
Max sats
Memo
Metadata
Min sats
Minimum acceptable expiration time for BOLT11 for refunds
Name
New password
Next
Non-admins can access the User Creation API Endpoint
Non-admins can create Hot Wallets for their Store
Non-admins can import Hot Wallets for their Store
Non-admins can use the Internal Lightning Node for their Store
Non-admins cannot access the User Creation API Endpoint
Notification Email
Notification URL
Notifications
Only enable the payment method after user explicitly chooses it
Optional seed passphrase
Order Id
Override the block explorers used
Pair to
Password
Password (leave blank to generate invite-link)
Pay Button
PayJoin BIP21
Payment
Payment invalid if transactions fails to confirm after invoice expiration
Payments
Payout Methods
Payout Processors
Payouts
Plugin server
Plugins
Point of Sale
Point of Sale Style
Policies
Preferred Price Source
Print display
Product list
Product list with cart
Profile Picture
PSBT content
PSBT to combine with
Public Key
Pull Payments
Rate Rules
Rates
Recommended fee confirmation target blocks
Recovery Code
Redirect invoice to redirect url automatically after paid
Redirect URL
Regenerate code
Register
Remember me
Remember this machine
Remove
Reporting
Request contributor data on checkout
Request customer data on checkout
Request Pairing
Requests
Reset goal every
REST Uri
Role
Roles
Root fingerprint
Save
Scope
Search engines can index this site
Security device (FIDO2)
Select
Select the Default Currency during Store Creation
Select the payout method used for refund
Send test webhook
Server Name
Server Settings
Services
Set Password
Settings
Shop Name
Shopify
Show "Pay in wallet" button
Show a timer minutes before invoice expiration
Show plugins in pre-release
Show recommended fee
Show the payment list in the public receipt page
Show the QR code of the receipt in the public receipt page
Show the store header
Sign in
Sort contribution perks by popularity
Sounds to play when a payment is made. One sound per line
Specify the amount and currency for the refund
Start date
Starting index
Store
Store Id
Store Name
Store Settings
Store Website
Submit
Subtract fees from amount
Support URL
Supported Transaction Currencies
Target Amount
Test Email
Text to display in the tip input
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
Theme
Tip percentage amounts (comma separated)
Translations
Two-Factor Authentication
Unarchive this store
Unify on-chain and lightning payment URL/QR code
Update Password
Update Webhook
Upload PSBT from file
Url of the Dynamic DNS service you are using
Use custom theme
Use SSL
User can input custom amount
User can input discount in %
Users
UTXOs to spend from
Verification Code
Wallet file
Wallet file content
Wallets
Webhooks
Welcome to {0}
Your dynamic DNS hostname
{
"... on every payment": "",
"... only if the customer makes more than one payment for the invoice": "",
"A given currency pair match the most specific rule. If two rules are matching and are as specific, the first rule will be chosen.": "",
"Access Tokens": "",
"Account": "",
"Account key": "",
"Account key path": "",
"Add additional fee (network fee) to invoice …": "",
"Add Address": "",
"Add Exchange Rate Spread": "",
"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 must approve new users": "",
"Administrator": "",
"Advanced rate rule scripting": "",
"Allow anyone to create invoice": "",
"Allow form for public use": "",
"Allow payee to create invoices with custom amounts": "",
"Allow payee to pass a comment": "",
"Allow Stores use the Server's SMTP email settings as their default": "",
"Always include non-witness UTXO if available": "",
"Amazon S3": "",
"Amount": "",
"API Key": "",
"API Keys": "",
"App": "",
"App Name": "",
"App Type": "",
"Application": "",
"Apply the brand color to the store's backend as well": "",
"Approve": "",
"Archive this store": "",
"At Least One": "",
"At Least Ten": "",
"Authenticator code": "",
"Auto-detect language on checkout": "",
"Automatically approve claims": "",
"Available Payment Methods": "",
"Azure Blob Storage": "",
"Backend's language": "",
"Batch size": "",
"BIP39 Seed (12/24 word mnemonic phrase) or HD private key (xprv...)": "",
"blocks": "",
"Brand Color": "",
"Branding": "",
"But now, what if you want to support <code>DOGE</code>? The problem with <code>DOGE</code> is that most exchange do not have any pair for it. But <code>bitpay</code> has a <code>DOGE_BTC</code> pair. <br />\r\n Luckily, the rule engine allow you to reference rules:": "",
"Buyer Email": "",
"Callback Notification URL": "",
"Can use hot wallet": "",
"Can use RPC import": "",
"Celebrate payment with confetti": "",
"Check releases on GitHub and notify when new BTCPay Server version is available": "",
"Checkout Appearance": "",
"Choose your import method": "",
"Choose your wallet option": "",
"Clone": "",
"Coingecko integration": "",
"Colors to rotate between with animation when a payment is made. One color per line.": "",
"Confirm new password": "",
"Confirm password": "",
"Connect an existing wallet": "",
"Connect hardware&nbsp;wallet": "",
"Connection string": "",
"Consider the invoice paid even if the paid amount is … % less than expected": "",
"Consider the invoice settled when the payment transaction …": "",
"Contact URL": "",
"Contact Us": "",
"Contribution Perks Template": "",
"Count all invoices created on the store as part of the goal": "",
"Create": "",
"Create a new app": "",
"Create a new wallet": "",
"Create Account": "",
"Create Form": "",
"Create Invoice": "",
"Create Pull Payment": "",
"Create Request": "",
"Create Store": "",
"Create Webhook": "",
"Create your account": "",
"Crowdfund": "",
"Currency": "",
"Current password": "",
"Custom": "",
"Custom CSS": "",
"Custom HTML title to display on Checkout page": "",
"Custom sound file for successful payment": "",
"Custom Theme Extension Type": "",
"Custom Theme File": "",
"Dashboard": "",
"days": "",
"Default currency": "",
"Default Currency Pairs": "",
"Default language on checkout": "",
"Default payment method on checkout": "",
"Default role for users on a new store": "",
"Delete this store": "",
"Derivation scheme": "",
"Derivation scheme format": "",
"Description": "",
"Description template of the lightning invoice": "",
"Destination Address": "",
"Dictionaries": "",
"Dictionaries enable you to translate the BTCPay Server backend into different languages.": "",
"Dictionary": "",
"Direct integration": "",
"Disable public user registration": "",
"Disable stores from using the server's email settings as backup": "",
"Discourage search engines from indexing this site": "",
"Display app on website root": "",
"Display contribution ranking": "",
"Display contribution value": "",
"Display item selection for keypad": "",
"Display Lightning payment amounts in Satoshis": "",
"Display the category list": "",
"Display the search bar": "",
"Display Title": "",
"Disqus Shortname": "",
"Do not allow additional contributions after target has been reached": "",
"Does not extend a BTCPay Server theme, fully custom": "",
"Domain": "",
"Domain name": "",
"Don't create UTXO change": "",
"Email": "",
"Email address": "",
"Email confirmation required": "",
"Email confirmed?": "",
"Emails": "",
"Enable background animations on new payments": "",
"Enable Disqus Comments": "",
"Enable experimental features": "",
"Enable LNURL": "",
"Enable Payjoin/P2EP": "",
"Enable public receipt page for settled invoices": "",
"Enable public user registration": "",
"Enable sounds on checkout page": "",
"Enable sounds on new payments": "",
"Enable tips": "",
"End date": "",
"Enter extended public key": "",
"Enter wallet seed": "",
"Error": "",
"Expiration Date": "",
"Export": "",
"Extends the BTCPay Server Dark theme": "",
"Extends the BTCPay Server Light theme": "",
"Fallback": "",
"Featured Image URL": "",
"Fee rate (sat/vB)": "",
"Fee will be shown for BTC and LTC onchain payments only.": "",
"Files": "",
"Forgot password?": "",
"Form configuration (JSON)": "",
"Forms": "",
"Gap limit": "",
"Generate": "",
"Generate {0} Wallet": "",
"Generate a brand-new wallet to use": "",
"Generate API Key": "",
"Generate Key": "",
"Google Cloud Storage": "",
"GRPC SSL Cipher suite (GRPC_SSL_CIPHER_SUITES)": "",
"Has at least 1 confirmation": "",
"Has at least 2 confirmations": "",
"Has at least 6 confirmations": "",
"Hide Sensitive Info": "",
"Hot wallet": "",
"However, <code>kraken</code> does not support the <code>BTC_CAD</code> pair. For this reason you can add a rule mapping all <code>X_CAD</code> to <code>ndax</code>, a Canadian exchange.": "",
"However, explicitely setting specific pairs like this can be a bit difficult. Instead, you can define a rule <code>X_X</code> which will match any currency pair. The following example will use <code>kraken</code> for getting the rate of any currency pair.": "",
"I don't have a wallet": "",
"I have a wallet": "",
"If a translation isnt available in the new dictionary, it will be searched in the fallback.": "",
"Image": "",
"Import {0} Wallet": "",
"Import an existing hardware or software wallet": "",
"Import wallet file": "",
"Import your public keys using our Vault application": "",
"Input the key string manually": "",
"Invitation URL": "",
"Invoice currency": "",
"Invoice expires if the full amount has not been paid after …": "",
"Invoice metadata": "",
"Invoices": "",
"Is administrator?": "",
"Is signing key": "",
"Is unconfirmed": "",
"It is worth noting that the inverses of those pairs are automatically supported as well.<br />\r\n It means that the rule <code>USD_DOGE = 1 / DOGE_USD</code> implicitely exists.": "",
"Item Description": "",
"Keypad": "",
"Let's get started": "",
"Lightning node (LNURL Auth)": "",
"LNURL Classic Mode": "",
"Local File System": "",
"Log in": "",
"Login Codes": "",
"Logo": "",
"Logout": "",
"Logs": "",
"Maintenance": "",
"Make Crowdfund Public": "",
"Manage Account": "",
"Manage Plugins": "",
"Master fingerprint": "",
"Max sats": "",
"Memo": "",
"Metadata": "",
"Min sats": "",
"Minimum acceptable expiration time for BOLT11 for refunds": "",
"Never add network fee": "",
"New password": "",
"Next": "",
"Non-admins can access the User Creation API Endpoint": "",
"Non-admins can create Hot Wallets for their Store": "",
"Non-admins can import Hot Wallets for their Store": "",
"Non-admins can use the Internal Lightning Node for their Store": "",
"Non-admins cannot access the User Creation API Endpoint": "",
"Not recommended": "",
"Notification Email": "",
"Notification URL": "",
"Notifications": "",
"Only enable the payment method after user explicitly chooses it": "",
"Optional seed passphrase": "",
"Order Id": "",
"Override the block explorers used": "",
"Pair to": "",
"Password": "",
"Password (leave blank to generate invite-link)": "",
"Pay Button": "",
"PayJoin BIP21": "",
"Payment": "",
"Payment invalid if transactions fails to confirm … after invoice expiration": "",
"Payments": "",
"Payout Methods": "",
"Payout Processors": "",
"Payouts": "",
"Please enable JavaScript for this option to be available": "",
"Please note that creating a hot wallet is not supported by this instance for non administrators.": "",
"Plugin server": "",
"Plugins": "",
"Point of Sale": "",
"Point of Sale Style": "",
"Policies": "",
"Preferred Price Source": "",
"Print display": "",
"Product list": "",
"Product list with cart": "",
"Profile Picture": "",
"Provide the 12 or 24 word recovery seed": "",
"PSBT content": "",
"PSBT to combine with…": "",
"Public Key": "",
"Pull Payments": "",
"Rate Rules": "",
"Rate script allows you to express precisely how you want to calculate rates for currency pairs.": "",
"Rates": "",
"Recommended": "",
"Recommended fee confirmation target blocks": "",
"Recovery Code": "",
"Redirect invoice to redirect url automatically after paid": "",
"Redirect URL": "",
"Register": "",
"Remember me": "",
"Remember this machine": "",
"Remove": "",
"Reporting": "",
"Request contributor data on checkout": "",
"Request customer data on checkout": "",
"Request Pairing": "",
"Requests": "",
"Required Confirmations": "",
"Reset goal every": "",
"Reset Password": "",
"REST Uri": "",
"Role": "",
"Roles": "",
"Root fingerprint": "",
"Save": "",
"Scan wallet QR code": "",
"Scope": "",
"Scripting": "",
"Search engines can index this site": "",
"Security device (FIDO2)": "",
"Select": "",
"Select the Default Currency during Store Creation": "",
"Select the payout method used for refund": "",
"Send invitation email": "",
"Send test webhook": "",
"Server Name": "",
"Server Settings": "",
"Services": "",
"Set Password": "",
"Set to default settings": "",
"Settings": "",
"Setup {0} Wallet": "",
"Shop Name": "",
"Shopify": "",
"Show \"Pay in wallet\" button": "",
"Show a timer … minutes before invoice expiration": "",
"Show plugins in pre-release": "",
"Show recommended fee": "",
"Show the payment list in the public receipt page": "",
"Show the QR code of the receipt in the public receipt page": "",
"Show the store header": "",
"Sign in": "",
"Sort contribution perks by popularity": "",
"Sounds to play when a payment is made. One sound per line": "",
"Specify the amount and currency for the refund": "",
"Start date": "",
"Starting index": "",
"Store": "",
"Store Id": "",
"Store Name": "",
"Store Settings": "",
"Store Speed Policy": "",
"Store Website": "",
"Submit": "",
"Subtract fees from amount": "",
"Support URL": "",
"Supported by BlueWallet, Cobo Vault, Passport and Specter DIY": "",
"Supported Transaction Currencies": "",
"Target Amount": "",
"Test Email": "",
"Test Results:": "",
"Testing": "",
"Text to display in the tip input": "",
"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": "",
"The following methods assume that you already have an existing&nbsp;wallet created and backed up.": "",
"The script language is composed of several rules composed of a currency pair and a mathematic expression.\r\n The example below will use <code>kraken</code> for both <code>LTC_USD</code> and <code>BTC_USD</code> pairs.": "",
"Theme": "",
"Tip percentage amounts (comma separated)": "",
"Translations": "",
"Two-Factor Authentication": "",
"Unarchive this store": "",
"Unify on-chain and lightning payment URL/QR code": "",
"Update Password": "",
"Update Webhook": "",
"Upload a file exported from your wallet": "",
"Upload PSBT from file…": "",
"Url of the Dynamic DNS service you are using": "",
"Use custom theme": "",
"Use SSL": "",
"User can input custom amount": "",
"User can input discount in %": "",
"Users": "",
"UTXOs to spend from": "",
"Verification Code": "",
"View-Only Wallet File": "",
"Wallet file": "",
"Wallet file content": "",
"Wallet Keys File": "",
"Wallet Password": "",
"Wallet's private key is erased from the server. Higher security. To spend, you have to manually input the private key or import it into an external wallet.": "",
"Wallet's private key is stored on the server. Spending the funds you received is convenient. To minimize the risk of theft, regularly withdraw funds to a different wallet.": "",
"Wallets": "",
"Watch-only wallet": "",
"Webhooks": "",
"Welcome to {0}": "",
"With <code>DOGE_USD</code> will be expanded to <code>bitpay(DOGE_BTC) * kraken(BTC_USD)</code>. And <code>DOGE_CAD</code> will be expanded to <code>bitpay(DOGE_BTC) * ndax(BTC_CAD)</code>. <br />\r\n However, we advise you to write it that way to increase coverage so that <code>DOGE_BTC</code> is also supported:": "",
"You really should not type your seed into a device that is connected to the internet.": "",
"Your dynamic DNS hostname": "",
"Zero Confirmation": ""
}
""";
Default = Translations.CreateFromText(knownTranslations);
Default = Translations.CreateFromJson(knownTranslations);
Default = new Translations(new KeyValuePair<string, string>[]
{
// You can add additional hard coded default here

View file

@ -53,25 +53,6 @@ namespace BTCPayServer.Services
return new Translations(translations
.Select(t => KeyValuePair.Create(t.key, t.value)));
}
public static Translations CreateFromText(string text)
{
text = (text ?? "").Replace("\r\n", "\n");
var translations = new List<(string key, string? value)>();
foreach (var line in text.Split("\n", StringSplitOptions.RemoveEmptyEntries))
{
var splitted = line.Split("=>", StringSplitOptions.RemoveEmptyEntries);
if (splitted is [var key, var value])
{
translations.Add((key, value));
}
else if (splitted is [var key2])
{
translations.Add((key2, key2));
}
}
return new Translations(translations
.Select(t => KeyValuePair.Create(t.key, t.value)));
}
public Translations(IEnumerable<KeyValuePair<string, string?>> records) : this (records, null)
{

View file

@ -130,9 +130,9 @@
@* For whatever reason wrapping the select with this div fixes this Safari bug: https://github.com/btcpayserver/btcpayserver/issues/3699 *@
<div class="overflow-hidden">
<select asp-for="NetworkFeeMode" class="form-select w-auto">
<option value="MultiplePaymentsOnly">... only if the customer makes more than one payment for the invoice</option>
<option value="Always">... on every payment</option>
<option value="Never">Never add network fee</option>
<option value="MultiplePaymentsOnly" text-translate="true">... only if the customer makes more than one payment for the invoice</option>
<option value="Always" text-translate="true">... on every payment</option>
<option value="Never" text-translate="true">Never add network fee</option>
</select>
</div>
</div>
@ -162,7 +162,7 @@
<label asp-for="BOLT11Expiration" class="form-label"></label>
<div class="input-group">
<input inputmode="numeric" asp-for="BOLT11Expiration" class="form-control" style="max-width:12ch;"/>
<span class="input-group-text">days</span>
<span class="input-group-text" text-translate="true">days</span>
</div>
<span asp-validation-for="BOLT11Expiration" class="text-danger"></span>
</div>
@ -183,10 +183,10 @@
<vc:icon symbol="info"/>
</a>
<select asp-for="SpeedPolicy" class="form-select w-auto" onchange="document.getElementById('unconfirmed-warning').hidden = this.value !== '0'">
<option value="0">Is unconfirmed</option>
<option value="1">Has at least 1 confirmation</option>
<option value="3">Has at least 2 confirmations</option>
<option value="2">Has at least 6 confirmations</option>
<option value="0" text-translate="true">Is unconfirmed</option>
<option value="1" text-translate="true">Has at least 1 confirmation</option>
<option value="3" text-translate="true">Has at least 2 confirmations</option>
<option value="2" text-translate="true">Has at least 6 confirmations</option>
</select>
<p class="info-note my-3 text-warning" id="unconfirmed-warning" role="alert" hidden="@(Model.SpeedPolicy != 0)">
<vc:icon symbol="warning"/>
@ -205,14 +205,14 @@
<input asp-for="ShowRecommendedFee" type="checkbox" class="btcpay-toggle me-3" />
<div>
<label asp-for="ShowRecommendedFee" class="form-check-label"></label>
<div class="form-text">Fee will be shown for BTC and LTC onchain payments only.</div>
<div class="form-text" text-translate="true">Fee will be shown for BTC and LTC onchain payments only.</div>
</div>
</div>
<div class="form-group">
<label asp-for="RecommendedFeeBlockTarget" class="form-label"></label>
<div class="input-group">
<input inputmode="numeric" asp-for="RecommendedFeeBlockTarget" class="form-control" min="1" style="max-width:10ch" />
<span class="input-group-text">blocks</span>
<span class="input-group-text" text-translate="true">blocks</span>
</div>
<span asp-validation-for="RecommendedFeeBlockTarget" class="text-danger"></span>
</div>

View file

@ -1,7 +1,10 @@
@model WalletSetupViewModel
@inject Microsoft.Extensions.Localization.IStringLocalizer StringLocalizer
@{
Layout = "_LayoutWalletSetup";
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"Generate {Model.CryptoCode} Wallet", $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
var title = StringLocalizer["Generate {0} Wallet", Model.CryptoCode];
ViewData.SetActivePage(StoreNavPages.OnchainSettings, title, $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
}
@section Navbar {
@ -10,7 +13,7 @@
</a>
}
<h1 class="text-center">Choose your wallet option</h1>
<h1 class="text-center" text-translate="true">Choose your wallet option</h1>
<div class="list-group mt-5">
@if (Model.CanUseHotWallet)
@ -20,11 +23,9 @@
<vc:icon symbol="wallet-hot"/>
</div>
<div class="content">
<h4>Hot wallet</h4>
<p class="mb-0 text-secondary">
Wallet's private key is stored on the server.
Spending the funds you received is convenient.
To minimize the risk of theft, regularly withdraw funds to a different wallet.
<h4 text-translate="true">Hot wallet</h4>
<p class="mb-0 text-secondary" text-translate="true">
Wallet's private key is stored on the server. Spending the funds you received is convenient. To minimize the risk of theft, regularly withdraw funds to a different wallet.
</p>
</div>
<vc:icon symbol="caret-right"/>
@ -37,8 +38,8 @@
<vc:icon symbol="wallet-hot"/>
</div>
<div class="content">
<h4>Hot wallet</h4>
<p class="mb-0">Please note that creating a hot wallet is not supported by this instance for non administrators.</p>
<h4 text-translate="true">Hot wallet</h4>
<p class="mb-0" text-translate="true">Please note that creating a hot wallet is not supported by this instance for non administrators.</p>
</div>
</div>
}
@ -50,10 +51,9 @@
<vc:icon symbol="wallet-watchonly"/>
</div>
<div class="content">
<h4>Watch-only wallet</h4>
<p class="mb-0 text-secondary">
Wallet's private key is erased from the server. Higher security.
To spend, you have to manually input the private key or import it into an external wallet.
<h4 text-translate="true">Watch-only wallet</h4>
<p class="mb-0 text-secondary" text-translate="true">
Wallet's private key is erased from the server. Higher security. To spend, you have to manually input the private key or import it into an external wallet.
</p>
</div>
<vc:icon symbol="caret-right" />

View file

@ -1,8 +1,12 @@
@model WalletSetupViewModel
@inject Microsoft.Extensions.Localization.IStringLocalizer StringLocalizer
@inject BTCPayNetworkProvider BTCPayNetworkProvider
@{
Layout = "_LayoutWalletSetup";
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"Import {Model.CryptoCode} Wallet", $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
var title = StringLocalizer["Import {0} Wallet", Model.CryptoCode];
ViewData.SetActivePage(StoreNavPages.OnchainSettings, title, $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
}
@section Navbar {
@ -12,8 +16,8 @@
}
<header class="text-center">
<h1>Choose your import method</h1>
<p class="lead text-secondary mt-3">The following methods assume that you already have an existing&nbsp;wallet created and backed up.</p>
<h1 text-translate="true">Choose your import method</h1>
<p class="lead text-secondary mt-3" text-translate="true">The following methods assume that you already have an existing&nbsp;wallet created and backed up.</p>
</header>
<style>
.icon.icon-wallet-xpub,
@ -31,10 +35,10 @@
</div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div>
<h4>Connect hardware&nbsp;wallet</h4>
<p class="mb-0 text-secondary">Import your public keys using our Vault application</p>
<h4 text-translate="true">Connect hardware&nbsp;wallet</h4>
<p class="mb-0 text-secondary" text-translate="true">Import your public keys using our Vault application</p>
</div>
<small class="d-block text-primary mt-2 mt-lg-0">Recommended</small>
<small class="d-block text-primary mt-2 mt-lg-0" text-translate="true">Recommended</small>
</div>
<vc:icon symbol="caret-right" />
</a>
@ -45,10 +49,10 @@
</div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div>
<h4>Connect hardware&nbsp;wallet</h4>
<p class="mb-0">Please enable JavaScript for this option to be available</p>
<h4 text-translate="true">Connect hardware&nbsp;wallet</h4>
<p class="mb-0" text-translate="true">Please enable JavaScript for this option to be available</p>
</div>
<small class="d-block text-primary mt-2 mt-lg-0">Recommended</small>
<small class="d-block text-primary mt-2 mt-lg-0" text-translate="true">Recommended</small>
</div>
</div>
</noscript>
@ -63,10 +67,10 @@
</div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div>
<h4>Import wallet file</h4>
<p class="mb-0 text-secondary">Upload a file exported from your wallet</p>
<h4 text-translate="true">Import wallet file</h4>
<p class="mb-0 text-secondary" text-translate="true">Upload a file exported from your wallet</p>
</div>
<small class="d-block text-primary mt-2 mt-lg-0">Recommended</small>
<small class="d-block text-primary mt-2 mt-lg-0" text-translate="true">Recommended</small>
</div>
<vc:icon symbol="caret-right" />
</a>
@ -78,8 +82,8 @@
<vc:icon symbol="wallet-xpub"/>
</div>
<div class="content">
<h4>Enter extended public key</h4>
<p class="mb-0 text-secondary">Input the key string manually</p>
<h4 text-translate="true">Enter extended public key</h4>
<p class="mb-0 text-secondary" text-translate="true">Input the key string manually</p>
</div>
<vc:icon symbol="caret-right" />
</a>
@ -91,8 +95,8 @@
<vc:icon symbol="scan-qr"/>
</div>
<div class="content">
<h4>Scan wallet QR code</h4>
<p class="mb-0 text-secondary">Supported by BlueWallet, Cobo Vault, Passport and Specter DIY</p>
<h4 text-translate="true">Scan wallet QR code</h4>
<p class="mb-0 text-secondary" text-translate="true">Supported by BlueWallet, Cobo Vault, Passport and Specter DIY</p>
</div>
<vc:icon symbol="caret-right" />
</a>
@ -102,8 +106,8 @@
<vc:icon symbol="scan-qr"/>
</div>
<div class="content">
<h4>Scan wallet QR code</h4>
<p class="mb-0">Please enable JavaScript for this option to be available</p>
<h4 text-translate="true">Scan wallet QR code</h4>
<p class="mb-0" text-translate="true">Please enable JavaScript for this option to be available</p>
</div>
</div>
</noscript>
@ -116,10 +120,13 @@
</div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div>
<h4>Enter wallet seed</h4>
<p class="mb-0 text-secondary">Provide the 12 or 24 word recovery seed</p>
<h4 text-translate="true">Enter wallet seed</h4>
<p class="mb-0 text-secondary" text-translate="true">Provide the 12 or 24 word recovery seed</p>
</div>
<small class="d-block text-danger mt-2 mt-lg-0" data-bs-toggle="tooltip" data-bs-placement="top" title="You really should not type your seed into a device that is connected to the internet.">Not recommended <vc:icon symbol="info"/></small>
@{
var shouldNotTypeSeed = StringLocalizer["You really should not type your seed into a device that is connected to the internet."];
}
<small class="d-block text-danger mt-2 mt-lg-0" data-bs-toggle="tooltip" data-bs-placement="top" title="@shouldNotTypeSeed"><span text-translate="true">Not recommended</span> <vc:icon symbol="info" /></small>
</div>
<vc:icon symbol="caret-right" />
</a>

View file

@ -23,15 +23,15 @@
@if (Model.ShowScripting)
{
<div class="form-group">
<h5>Scripting</h5>
<p>Rate script allows you to express precisely how you want to calculate rates for currency pairs.</p>
<h5 text-translate="true">Scripting</h5>
<p html-translate="true">Rate script allows you to express precisely how you want to calculate rates for currency pairs.</p>
<p>We are retrieving the rate of each exchange either directly, or via <a href="https://www.coingecko.com/" target="_blank" rel="noreferrer noopener">CoinGecko (free)</a>.</p>
<div class="accordion" id="accordion-info">
<div class="accordion-item">
<h2 class="accordion-header" id="direct-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#direct-content" aria-expanded="false" aria-controls="direct-content">
Direct integration
<span text-translate="true">Direct integration</span>
<vc:icon symbol="caret-down"/>
</button>
</h2>
@ -47,7 +47,7 @@
<div class="accordion-item">
<h2 class="accordion-header" id="coingecko-header">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#coingecko-content" aria-expanded="false" aria-controls="coingecko-content">
Coingecko integration
<span text-translate="true">Coingecko integration</span>
<vc:icon symbol="caret-down"/>
</button>
</h2>
@ -65,7 +65,7 @@
}
@if (Model.TestRateRules != null)
{
<h5>Test Results:</h5>
<h5 text-translate="true">Test Results:</h5>
<div class="table-responsive-md">
<table class="table table-hover">
<tbody>
@ -96,26 +96,26 @@
@if (Model.ShowScripting)
{
<div id="help" class="collapse text-start">
<p>
<p html-translate="true">
The script language is composed of several rules composed of a currency pair and a mathematic expression.
The example below will use <code>kraken</code> for both <code>LTC_USD</code> and <code>BTC_USD</code> pairs.
</p>
<pre><code class="text hljs">LTC_USD = kraken(LTC_USD);
BTC_USD = kraken(BTC_USD);</code></pre>
<p>However, explicitely setting specific pairs like this can be a bit difficult. Instead, you can define a rule <code>X_X</code> which will match any currency pair. The following example will use <code>kraken</code> for getting the rate of any currency pair.</p>
<p html-translate="true">However, explicitely setting specific pairs like this can be a bit difficult. Instead, you can define a rule <code>X_X</code> which will match any currency pair. The following example will use <code>kraken</code> for getting the rate of any currency pair.</p>
<pre><code class="text hljs">X_X = kraken(X_X);</code></pre>
<p>However, <code>kraken</code> does not support the <code>BTC_CAD</code> pair. For this reason you can add a rule mapping all <code>X_CAD</code> to <code>ndax</code>, a Canadian exchange.</p>
<p html-translate="true">However, <code>kraken</code> does not support the <code>BTC_CAD</code> pair. For this reason you can add a rule mapping all <code>X_CAD</code> to <code>ndax</code>, a Canadian exchange.</p>
<pre><code class="text hljs">X_CAD = ndax(X_CAD);
X_X = kraken(X_X);</code></pre>
<p>A given currency pair match the most specific rule. If two rules are matching and are as specific, the first rule will be chosen.</p>
<p>
<p html-translate="true">A given currency pair match the most specific rule. If two rules are matching and are as specific, the first rule will be chosen.</p>
<p html-translate="true">
But now, what if you want to support <code>DOGE</code>? The problem with <code>DOGE</code> is that most exchange do not have any pair for it. But <code>bitpay</code> has a <code>DOGE_BTC</code> pair. <br />
Luckily, the rule engine allow you to reference rules:
</p>
<pre><code class="text hljs">DOGE_X = bitpay(DOGE_BTC) * BTC_X;
X_CAD = ndax(X_CAD);
X_X = kraken(X_X);</code></pre>
<p>
<p html-translate="true">
With <code>DOGE_USD</code> will be expanded to <code>bitpay(DOGE_BTC) * kraken(BTC_USD)</code>. And <code>DOGE_CAD</code> will be expanded to <code>bitpay(DOGE_BTC) * ndax(BTC_CAD)</code>. <br />
However, we advise you to write it that way to increase coverage so that <code>DOGE_BTC</code> is also supported:
</p>
@ -123,7 +123,7 @@ X_X = kraken(X_X);</code></pre>
DOGE_BTC = bitpay(DOGE_BTC);
X_CAD = ndax(X_CAD);
X_X = kraken(X_X);</code></pre>
<p>
<p html-translate="true">
It is worth noting that the inverses of those pairs are automatically supported as well.<br />
It means that the rule <code>USD_DOGE = 1 / DOGE_USD</code> implicitely exists.
</p>
@ -136,7 +136,7 @@ X_X = kraken(X_X);</code></pre>
<textarea asp-for="Script" rows="20" cols="80" class="form-control"></textarea>
<span asp-validation-for="Script" class="text-danger"></span>
<p>
<button type="button" class="btn btn-link text-secondary px-0" id="ResetDefaults">Set to default settings</button>
<button type="button" class="btn btn-link text-secondary px-0" id="ResetDefaults" text-translate="true">Set to default settings</button>
</p>
</div>
}
@ -155,7 +155,7 @@ X_X = kraken(X_X);</code></pre>
<label class="d-flex align-items-center">
<button type="submit" id="ShowScripting" class="btcpay-toggle me-3 @if (Model.ShowScripting) { @("btcpay-toggle--active") }" value="scripting-@(Model.ShowScripting ? "off" : "on")" name="command" data-bs-toggle="modal" data-bs-target="#ConfirmModal" permission="@Policies.CanModifyStoreSettings">@(Model.ShowScripting ? "Disable" : "Enable") advanced rate rule scripting</button>
<div>
<span>Advanced rate rule scripting</span>
<span text-translate="true">Advanced rate rule scripting</span>
<div class="form-text">
@(Model.ShowScripting ? "Disabling will delete your rate script." : "Enabling will modify your current rate sources. This is a feature for advanced users.")
</div>
@ -170,7 +170,7 @@ X_X = kraken(X_X);</code></pre>
</div>
<span asp-validation-for="Spread" class="text-danger"></span>
</div>
<h3 class="mt-5 mb-3">Testing</h3>
<h3 class="mt-5 mb-3" text-translate="true">Testing</h3>
<div class="form-group">
<label asp-for="ScriptTest" class="form-label">Currency pairs to test against your rule (e.g. <code>DOGE_USD,DOGE_CAD,BTC_CAD,BTC_USD</code>)</label>
@ -181,7 +181,7 @@ X_X = kraken(X_X);</code></pre>
<span asp-validation-for="ScriptTest" class="text-danger"></span>
</div>
<h3 class="mt-5 mb-3">Default Currency Pairs</h3>
<h3 class="mt-5 mb-3" text-translate="true">Default Currency Pairs</h3>
<div class="form-group">
<label asp-for="DefaultCurrencyPairs" class="form-label">Query pairs via REST by querying <a asp-controller="BitpayRate" asp-action="GetRates2" asp-route-storeId="@Model.StoreId" target="_blank">this link</a> without the need to specify currencyPairs.</label>
<input asp-for="DefaultCurrencyPairs" class="form-control" placeholder="BTC_USD, BTC_CAD" />

View file

@ -1,21 +1,25 @@
@model WalletSetupViewModel
@inject Microsoft.Extensions.Localization.IStringLocalizer StringLocalizer
@{
Layout = "_LayoutWalletSetup";
ViewData.SetActivePage(StoreNavPages.OnchainSettings, $"Setup {Model.CryptoCode} Wallet", $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
var title = this.StringLocalizer["Setup {0} Wallet", Model.CryptoCode];
ViewData.SetActivePage(StoreNavPages.OnchainSettings, title, $"{Context.GetStoreData().Id}-{Model.CryptoCode}");
}
<h1 class="text-center">Let's get started</h1>
<h1 class="text-center" text-translate="true">Let's get started</h1>
<br>
<div class="mt-5">
<h3 class="my-4">I have a wallet</h3>
<h3 class="my-4" text-translate="true">I have a wallet</h3>
<div class="list-group">
<a asp-controller="UIStores" asp-action="ImportWallet" asp-route-storeId="@Model.StoreId" asp-route-cryptoCode="@Model.CryptoCode" id="ImportWalletOptionsLink" class="list-group-item list-group-item-action">
<div class="image">
<vc:icon symbol="wallet-existing"/>
</div>
<div class="content">
<h4>Connect an existing wallet</h4>
<p class="mb-0 text-secondary">Import an existing hardware or software wallet</p>
<h4 text-translate="true">Connect an existing wallet</h4>
<p class="mb-0 text-secondary" text-translate="true">Import an existing hardware or software wallet</p>
</div>
<vc:icon symbol="caret-right" />
</a>
@ -24,15 +28,15 @@
<br>
<div class="mt-5">
<h3 class="my-4">I don't have a wallet</h3>
<h3 class="my-4" text-translate="true">I don't have a wallet</h3>
<div class="list-group">
<a asp-controller="UIStores" asp-action="GenerateWallet" asp-route-storeId="@Model.StoreId" asp-route-cryptoCode="@Model.CryptoCode" id="GenerateWalletLink" class="list-group-item list-group-item-action">
<div class="image">
<vc:icon symbol="wallet-new"/>
</div>
<div class="content">
<h4>Create a new wallet</h4>
<p class="mb-0 text-secondary">Generate a brand-new wallet to use</p>
<h4 text-translate="true">Create a new wallet</h4>
<p class="mb-0 text-secondary" text-translate="true">Generate a brand-new wallet to use</p>
</div>
<vc:icon symbol="caret-right"/>
</a>