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 "Password" : "Cyphercode",
Welcome to {0} => Yo at {0} "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 // 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(); await tester.StartAsync();
var engine = tester.PayTester.GetService<RazorProjectEngine>(); var engine = tester.PayTester.GetService<RazorProjectEngine>();
@ -360,12 +360,15 @@ retry:
{ {
var filePath = file.FullName; var filePath = file.FullName;
var txt = File.ReadAllText(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))
foreach (Match match in matches)
{ {
defaultTranslatedKeys.Add(match.Groups[1].Value); var matches = Regex.Matches(txt, localizer + "\\[\"(.*?)\"[\\],]");
foreach (Match match in matches)
{
defaultTranslatedKeys.Add(match.Groups[1].Value);
}
} }
} }
@ -379,12 +382,18 @@ retry:
} }
defaultTranslatedKeys = defaultTranslatedKeys.Select(d => d.Trim()).Distinct().OrderBy(o => o).ToList(); 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 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("\"\"\"");
var endIdx = defaultTranslation.LastIndexOf("\"\"\""); var endIdx = defaultTranslation.LastIndexOf("\"\"\"");
var content = defaultTranslation.Substring(0, startIdx + 3); 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); content += defaultTranslation.Substring(endIdx);
File.WriteAllText(path, content); File.WriteAllText(path, content);
} }

View file

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

View file

@ -64,7 +64,7 @@ namespace BTCPayServer.Hosting
continue; continue;
} }
var savedHash = dictionary.Metadata.ToObject<DictionaryFileMetadata>().Hash; 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()))); var currentHash = new uint256(SHA256.HashData(Encoding.UTF8.GetBytes(translations.ToJsonFormat())));
if (savedHash != currentHash) if (savedHash != currentHash)

View file

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

View file

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

View file

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

View file

@ -1,8 +1,12 @@
@model WalletSetupViewModel @model WalletSetupViewModel
@inject Microsoft.Extensions.Localization.IStringLocalizer StringLocalizer
@inject BTCPayNetworkProvider BTCPayNetworkProvider @inject BTCPayNetworkProvider BTCPayNetworkProvider
@{ @{
Layout = "_LayoutWalletSetup"; 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 { @section Navbar {
@ -12,8 +16,8 @@
} }
<header class="text-center"> <header class="text-center">
<h1>Choose your import method</h1> <h1 text-translate="true">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> <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> </header>
<style> <style>
.icon.icon-wallet-xpub, .icon.icon-wallet-xpub,
@ -31,10 +35,10 @@
</div> </div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2"> <div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div> <div>
<h4>Connect hardware&nbsp;wallet</h4> <h4 text-translate="true">Connect hardware&nbsp;wallet</h4>
<p class="mb-0 text-secondary">Import your public keys using our Vault application</p> <p class="mb-0 text-secondary" text-translate="true">Import your public keys using our Vault application</p>
</div> </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>
<vc:icon symbol="caret-right" /> <vc:icon symbol="caret-right" />
</a> </a>
@ -45,10 +49,10 @@
</div> </div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2"> <div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div> <div>
<h4>Connect hardware&nbsp;wallet</h4> <h4 text-translate="true">Connect hardware&nbsp;wallet</h4>
<p class="mb-0">Please enable JavaScript for this option to be available</p> <p class="mb-0" text-translate="true">Please enable JavaScript for this option to be available</p>
</div> </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>
</div> </div>
</noscript> </noscript>
@ -63,10 +67,10 @@
</div> </div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2"> <div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div> <div>
<h4>Import wallet file</h4> <h4 text-translate="true">Import wallet file</h4>
<p class="mb-0 text-secondary">Upload a file exported from your wallet</p> <p class="mb-0 text-secondary" text-translate="true">Upload a file exported from your wallet</p>
</div> </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>
<vc:icon symbol="caret-right" /> <vc:icon symbol="caret-right" />
</a> </a>
@ -78,8 +82,8 @@
<vc:icon symbol="wallet-xpub"/> <vc:icon symbol="wallet-xpub"/>
</div> </div>
<div class="content"> <div class="content">
<h4>Enter extended public key</h4> <h4 text-translate="true">Enter extended public key</h4>
<p class="mb-0 text-secondary">Input the key string manually</p> <p class="mb-0 text-secondary" text-translate="true">Input the key string manually</p>
</div> </div>
<vc:icon symbol="caret-right" /> <vc:icon symbol="caret-right" />
</a> </a>
@ -91,8 +95,8 @@
<vc:icon symbol="scan-qr"/> <vc:icon symbol="scan-qr"/>
</div> </div>
<div class="content"> <div class="content">
<h4>Scan wallet QR code</h4> <h4 text-translate="true">Scan wallet QR code</h4>
<p class="mb-0 text-secondary">Supported by BlueWallet, Cobo Vault, Passport and Specter DIY</p> <p class="mb-0 text-secondary" text-translate="true">Supported by BlueWallet, Cobo Vault, Passport and Specter DIY</p>
</div> </div>
<vc:icon symbol="caret-right" /> <vc:icon symbol="caret-right" />
</a> </a>
@ -102,8 +106,8 @@
<vc:icon symbol="scan-qr"/> <vc:icon symbol="scan-qr"/>
</div> </div>
<div class="content"> <div class="content">
<h4>Scan wallet QR code</h4> <h4 text-translate="true">Scan wallet QR code</h4>
<p class="mb-0">Please enable JavaScript for this option to be available</p> <p class="mb-0" text-translate="true">Please enable JavaScript for this option to be available</p>
</div> </div>
</div> </div>
</noscript> </noscript>
@ -116,10 +120,13 @@
</div> </div>
<div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2"> <div class="content d-flex flex-column flex-lg-row align-items-lg-center justify-content-lg-between me-2">
<div> <div>
<h4>Enter wallet seed</h4> <h4 text-translate="true">Enter wallet seed</h4>
<p class="mb-0 text-secondary">Provide the 12 or 24 word recovery seed</p> <p class="mb-0 text-secondary" text-translate="true">Provide the 12 or 24 word recovery seed</p>
</div> </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> </div>
<vc:icon symbol="caret-right" /> <vc:icon symbol="caret-right" />
</a> </a>

View file

@ -23,15 +23,15 @@
@if (Model.ShowScripting) @if (Model.ShowScripting)
{ {
<div class="form-group"> <div class="form-group">
<h5>Scripting</h5> <h5 text-translate="true">Scripting</h5>
<p>Rate script allows you to express precisely how you want to calculate rates for currency pairs.</p> <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> <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" id="accordion-info">
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header" id="direct-header"> <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"> <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"/> <vc:icon symbol="caret-down"/>
</button> </button>
</h2> </h2>
@ -47,7 +47,7 @@
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header" id="coingecko-header"> <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"> <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"/> <vc:icon symbol="caret-down"/>
</button> </button>
</h2> </h2>
@ -65,7 +65,7 @@
} }
@if (Model.TestRateRules != null) @if (Model.TestRateRules != null)
{ {
<h5>Test Results:</h5> <h5 text-translate="true">Test Results:</h5>
<div class="table-responsive-md"> <div class="table-responsive-md">
<table class="table table-hover"> <table class="table table-hover">
<tbody> <tbody>
@ -96,26 +96,26 @@
@if (Model.ShowScripting) @if (Model.ShowScripting)
{ {
<div id="help" class="collapse text-start"> <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 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. The example below will use <code>kraken</code> for both <code>LTC_USD</code> and <code>BTC_USD</code> pairs.
</p> </p>
<pre><code class="text hljs">LTC_USD = kraken(LTC_USD); <pre><code class="text hljs">LTC_USD = kraken(LTC_USD);
BTC_USD = kraken(BTC_USD);</code></pre> 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> <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); <pre><code class="text hljs">X_CAD = ndax(X_CAD);
X_X = kraken(X_X);</code></pre> 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 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> <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 /> 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: Luckily, the rule engine allow you to reference rules:
</p> </p>
<pre><code class="text hljs">DOGE_X = bitpay(DOGE_BTC) * BTC_X; <pre><code class="text hljs">DOGE_X = bitpay(DOGE_BTC) * BTC_X;
X_CAD = ndax(X_CAD); X_CAD = ndax(X_CAD);
X_X = kraken(X_X);</code></pre> 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 /> 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: However, we advise you to write it that way to increase coverage so that <code>DOGE_BTC</code> is also supported:
</p> </p>
@ -123,7 +123,7 @@ X_X = kraken(X_X);</code></pre>
DOGE_BTC = bitpay(DOGE_BTC); DOGE_BTC = bitpay(DOGE_BTC);
X_CAD = ndax(X_CAD); X_CAD = ndax(X_CAD);
X_X = kraken(X_X);</code></pre> 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 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. It means that the rule <code>USD_DOGE = 1 / DOGE_USD</code> implicitely exists.
</p> </p>
@ -136,7 +136,7 @@ X_X = kraken(X_X);</code></pre>
<textarea asp-for="Script" rows="20" cols="80" class="form-control"></textarea> <textarea asp-for="Script" rows="20" cols="80" class="form-control"></textarea>
<span asp-validation-for="Script" class="text-danger"></span> <span asp-validation-for="Script" class="text-danger"></span>
<p> <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> </p>
</div> </div>
} }
@ -155,7 +155,7 @@ X_X = kraken(X_X);</code></pre>
<label class="d-flex align-items-center"> <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> <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> <div>
<span>Advanced rate rule scripting</span> <span text-translate="true">Advanced rate rule scripting</span>
<div class="form-text"> <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.") @(Model.ShowScripting ? "Disabling will delete your rate script." : "Enabling will modify your current rate sources. This is a feature for advanced users.")
</div> </div>
@ -170,7 +170,7 @@ X_X = kraken(X_X);</code></pre>
</div> </div>
<span asp-validation-for="Spread" class="text-danger"></span> <span asp-validation-for="Spread" class="text-danger"></span>
</div> </div>
<h3 class="mt-5 mb-3">Testing</h3> <h3 class="mt-5 mb-3" text-translate="true">Testing</h3>
<div class="form-group"> <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> <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> <span asp-validation-for="ScriptTest" class="text-danger"></span>
</div> </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"> <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> <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" /> <input asp-for="DefaultCurrencyPairs" class="form-control" placeholder="BTC_USD, BTC_CAD" />

View file

@ -1,21 +1,25 @@
@model WalletSetupViewModel @model WalletSetupViewModel
@inject Microsoft.Extensions.Localization.IStringLocalizer StringLocalizer
@{ @{
Layout = "_LayoutWalletSetup"; 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> <br>
<div class="mt-5"> <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"> <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"> <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"> <div class="image">
<vc:icon symbol="wallet-existing"/> <vc:icon symbol="wallet-existing"/>
</div> </div>
<div class="content"> <div class="content">
<h4>Connect an existing wallet</h4> <h4 text-translate="true">Connect an existing wallet</h4>
<p class="mb-0 text-secondary">Import an existing hardware or software wallet</p> <p class="mb-0 text-secondary" text-translate="true">Import an existing hardware or software wallet</p>
</div> </div>
<vc:icon symbol="caret-right" /> <vc:icon symbol="caret-right" />
</a> </a>
@ -24,15 +28,15 @@
<br> <br>
<div class="mt-5"> <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"> <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"> <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"> <div class="image">
<vc:icon symbol="wallet-new"/> <vc:icon symbol="wallet-new"/>
</div> </div>
<div class="content"> <div class="content">
<h4>Create a new wallet</h4> <h4 text-translate="true">Create a new wallet</h4>
<p class="mb-0 text-secondary">Generate a brand-new wallet to use</p> <p class="mb-0 text-secondary" text-translate="true">Generate a brand-new wallet to use</p>
</div> </div>
<vc:icon symbol="caret-right"/> <vc:icon symbol="caret-right"/>
</a> </a>