feat: more currencies, auto-detection, globe-only language toggle
- Add GBP, JPY, RUB, BRL currencies - Auto-detect currency from browser locale (de-CH→CHF, ru→RUB, etc.) - USD as default fallback - Language toggle: globe icon only (compact on mobile), full names in dropdown - Countdown text updates on language switch - CoinGecko proxy supports dynamic currency list
This commit is contained in:
@@ -15,7 +15,9 @@ if (file_exists($cacheFile)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = 'https://api.coingecko.com/api/v3/simple/price?ids=monero&vs_currencies=eur,usd,chf';
|
$currencies = $_GET['c'] ?? 'eur,usd,chf,gbp,jpy,rub,brl';
|
||||||
|
$currencies = preg_replace('/[^a-z,]/', '', strtolower($currencies));
|
||||||
|
$url = 'https://api.coingecko.com/api/v3/simple/price?ids=monero&vs_currencies=' . $currencies;
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
|||||||
34
app.js
34
app.js
@@ -2,7 +2,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// --- Config ---
|
// --- Config ---
|
||||||
const COINGECKO_API = '/api/rates.php';
|
const COINGECKO_API = '/api/rates.php?c=eur,usd,chf,gbp,jpy,rub,brl';
|
||||||
// Standard address (4..., 95 chars), Subaddress (8..., 95 chars), Integrated address (4..., 106 chars)
|
// Standard address (4..., 95 chars), Subaddress (8..., 95 chars), Integrated address (4..., 106 chars)
|
||||||
const XMR_STANDARD_REGEX = /^[48][1-9A-HJ-NP-Za-km-z]{94}$/;
|
const XMR_STANDARD_REGEX = /^[48][1-9A-HJ-NP-Za-km-z]{94}$/;
|
||||||
const XMR_INTEGRATED_REGEX = /^4[1-9A-HJ-NP-Za-km-z]{105}$/;
|
const XMR_INTEGRATED_REGEX = /^4[1-9A-HJ-NP-Za-km-z]{105}$/;
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
let fiatRates = null;
|
let fiatRates = null;
|
||||||
let ratesTimestamp = 0;
|
let ratesTimestamp = 0;
|
||||||
let countdownInterval = null;
|
let countdownInterval = null;
|
||||||
|
let countdownTick = null;
|
||||||
let ratesFailed = false;
|
let ratesFailed = false;
|
||||||
let invoiceCode = null; // short URL code for this invoice
|
let invoiceCode = null; // short URL code for this invoice
|
||||||
|
|
||||||
@@ -53,7 +54,35 @@
|
|||||||
let pdfLoaded = false;
|
let pdfLoaded = false;
|
||||||
let lastPaidData = null;
|
let lastPaidData = null;
|
||||||
|
|
||||||
|
// --- Currency Detection ---
|
||||||
|
function detectCurrency() {
|
||||||
|
var localeToCurrency = {
|
||||||
|
'de': 'EUR', 'fr': 'EUR', 'it': 'EUR', 'es': 'EUR', 'pt': 'EUR', 'nl': 'EUR',
|
||||||
|
'de-CH': 'CHF', 'fr-CH': 'CHF', 'it-CH': 'CHF',
|
||||||
|
'de-AT': 'EUR',
|
||||||
|
'en-GB': 'GBP',
|
||||||
|
'en-US': 'USD', 'en': 'USD',
|
||||||
|
'ja': 'JPY',
|
||||||
|
'ru': 'RUB',
|
||||||
|
'pt-BR': 'BRL'
|
||||||
|
};
|
||||||
|
var langs = navigator.languages || [navigator.language || 'en'];
|
||||||
|
for (var i = 0; i < langs.length; i++) {
|
||||||
|
var tag = langs[i];
|
||||||
|
if (localeToCurrency[tag]) {
|
||||||
|
currencySelect.value = localeToCurrency[tag];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var short = tag.substring(0, 2).toLowerCase();
|
||||||
|
if (localeToCurrency[short]) {
|
||||||
|
currencySelect.value = localeToCurrency[short];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// --- Init ---
|
// --- Init ---
|
||||||
|
detectCurrency();
|
||||||
fetchRates();
|
fetchRates();
|
||||||
loadFromHash() || loadSaved();
|
loadFromHash() || loadSaved();
|
||||||
registerSW();
|
registerSW();
|
||||||
@@ -77,6 +106,8 @@
|
|||||||
buildSummary(xmrAmount, desc, selectedDays);
|
buildSummary(xmrAmount, desc, selectedDays);
|
||||||
updatePageTitle(xmrAmount, desc);
|
updatePageTitle(xmrAmount, desc);
|
||||||
}
|
}
|
||||||
|
// Countdown text
|
||||||
|
if (countdownTick) countdownTick();
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Events ---
|
// --- Events ---
|
||||||
@@ -410,6 +441,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
countdownTick = tick;
|
||||||
tick();
|
tick();
|
||||||
countdownInterval = setInterval(tick, 60000); // Update every minute, not every second
|
countdownInterval = setInterval(tick, 60000); // Update every minute, not every second
|
||||||
}
|
}
|
||||||
|
|||||||
2
app.min.js
vendored
2
app.min.js
vendored
File diff suppressed because one or more lines are too long
4
i18n.js
4
i18n.js
@@ -376,10 +376,6 @@ var I18n = (function () {
|
|||||||
|
|
||||||
applyDOM(t);
|
applyDOM(t);
|
||||||
|
|
||||||
// Update toggle label
|
|
||||||
var cur = document.getElementById('langCurrent');
|
|
||||||
if (cur) cur.textContent = languages[lang].name;
|
|
||||||
|
|
||||||
// Update dropdown active state
|
// Update dropdown active state
|
||||||
document.querySelectorAll('.lang-option').forEach(function (btn) {
|
document.querySelectorAll('.lang-option').forEach(function (btn) {
|
||||||
btn.classList.toggle('active', btn.getAttribute('data-lang') === lang);
|
btn.classList.toggle('active', btn.getAttribute('data-lang') === lang);
|
||||||
|
|||||||
2
i18n.min.js
vendored
2
i18n.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -29,9 +29,13 @@
|
|||||||
<input type="number" id="amount" placeholder="0.00" min="0" step="any">
|
<input type="number" id="amount" placeholder="0.00" min="0" step="any">
|
||||||
<select id="currency" data-i18n-aria="aria_currency" aria-label="Currency">
|
<select id="currency" data-i18n-aria="aria_currency" aria-label="Currency">
|
||||||
<option value="XMR">XMR</option>
|
<option value="XMR">XMR</option>
|
||||||
<option value="EUR" selected>EUR</option>
|
<option value="EUR">EUR</option>
|
||||||
<option value="USD">USD</option>
|
<option value="USD" selected>USD</option>
|
||||||
<option value="CHF">CHF</option>
|
<option value="CHF">CHF</option>
|
||||||
|
<option value="GBP">GBP</option>
|
||||||
|
<option value="JPY">JPY</option>
|
||||||
|
<option value="RUB">RUB</option>
|
||||||
|
<option value="BRL">BRL</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="fiat-hint" id="fiatHint"></div>
|
<div class="fiat-hint" id="fiatHint"></div>
|
||||||
@@ -112,7 +116,6 @@
|
|||||||
<path d="M2 12h20"/>
|
<path d="M2 12h20"/>
|
||||||
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10A15.3 15.3 0 0 1 12 2z"/>
|
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10A15.3 15.3 0 0 1 12 2z"/>
|
||||||
</svg>
|
</svg>
|
||||||
<span id="langCurrent">English</span>
|
|
||||||
</button>
|
</button>
|
||||||
<div class="lang-dropdown" id="langDropdown"></div>
|
<div class="lang-dropdown" id="langDropdown"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user