feat: add language to topmenu + globals cleanup + i18n refactor (#3510)

This commit is contained in:
dni ⚡
2025-11-12 14:07:53 +00:00
committed by GitHub
parent 5e36bb4fcd
commit b6f533be24
15 changed files with 90 additions and 76 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+4 -2
View File
@@ -66,7 +66,7 @@ window.LNbits = {
}
newWallet.msat = data.balance_msat
newWallet.sat = Math.floor(data.balance_msat / 1000)
newWallet.fsat = new Intl.NumberFormat(window.LOCALE).format(
newWallet.fsat = new Intl.NumberFormat(window.i18n.global.locale).format(
newWallet.sat
)
if (newWallet.walletType === 'lightning-shared') {
@@ -105,7 +105,9 @@ window.LNbits = {
obj.msat = obj.amount
obj.sat = obj.msat / 1000
obj.tag = obj.extra?.tag
obj.fsat = new Intl.NumberFormat(window.LOCALE).format(obj.sat)
obj.fsat = new Intl.NumberFormat(window.i18n.global.locale).format(
obj.sat
)
obj.isIn = obj.amount > 0
obj.isOut = obj.amount < 0
obj.isPending = obj.status === 'pending'
@@ -0,0 +1,37 @@
window.app.component('lnbits-language-dropdown', {
template: '#lnbits-language-dropdown',
mixins: [window.windowMixin],
methods: {
activeLanguage(lang) {
return window.i18n.global.locale === lang
},
changeLanguage(newValue) {
this.g.locale = newValue
window.i18n.global.locale = newValue
this.$q.localStorage.set('lnbits.lang', newValue)
}
},
data() {
return {
langs: [
{value: 'en', label: 'English', display: '🇬🇧 EN'},
{value: 'de', label: 'Deutsch', display: '🇩🇪 DE'},
{value: 'es', label: 'Español', display: '🇪🇸 ES'},
{value: 'jp', label: '日本語', display: '🇯🇵 JP'},
{value: 'cn', label: '中文', display: '🇨🇳 CN'},
{value: 'fr', label: 'Français', display: '🇫🇷 FR'},
{value: 'it', label: 'Italiano', display: '🇮🇹 IT'},
{value: 'pi', label: 'Pirate', display: '🏴‍☠️ PI'},
{value: 'nl', label: 'Nederlands', display: '🇳🇱 NL'},
{value: 'we', label: 'Cymraeg', display: '🏴󠁧󠁢󠁷󠁬󠁳󠁿 CY'},
{value: 'pl', label: 'Polski', display: '🇵🇱 PL'},
{value: 'pt', label: 'Português', display: '🇵🇹 PT'},
{value: 'br', label: 'Português do Brasil', display: '🇧🇷 BR'},
{value: 'cs', label: 'Česky', display: '🇨🇿 CS'},
{value: 'sk', label: 'Slovensky', display: '🇸🇰 SK'},
{value: 'kr', label: '한국어', display: '🇰🇷 KR'},
{value: 'fi', label: 'Suomi', display: '🇫🇮 FI'}
]
}
}
})
+9 -32
View File
@@ -1,33 +1,3 @@
window.langs = [
{value: 'en', label: 'English', display: '🇬🇧 EN'},
{value: 'de', label: 'Deutsch', display: '🇩🇪 DE'},
{value: 'es', label: 'Español', display: '🇪🇸 ES'},
{value: 'jp', label: '日本語', display: '🇯🇵 JP'},
{value: 'cn', label: '中文', display: '🇨🇳 CN'},
{value: 'fr', label: 'Français', display: '🇫🇷 FR'},
{value: 'it', label: 'Italiano', display: '🇮🇹 IT'},
{value: 'pi', label: 'Pirate', display: '🏴‍☠️ PI'},
{value: 'nl', label: 'Nederlands', display: '🇳🇱 NL'},
{value: 'we', label: 'Cymraeg', display: '🏴󠁧󠁢󠁷󠁬󠁳󠁿 CY'},
{value: 'pl', label: 'Polski', display: '🇵🇱 PL'},
{value: 'pt', label: 'Português', display: '🇵🇹 PT'},
{value: 'br', label: 'Português do Brasil', display: '🇧🇷 BR'},
{value: 'cs', label: 'Česky', display: '🇨🇿 CS'},
{value: 'sk', label: 'Slovensky', display: '🇸🇰 SK'},
{value: 'kr', label: '한국어', display: '🇰🇷 KR'},
{value: 'fi', label: 'Suomi', display: '🇫🇮 FI'}
]
window.LOCALE = 'en'
window.dateFormat = 'YYYY-MM-DD HH:mm'
window.i18n = new VueI18n.createI18n({
locale: window.LOCALE,
fallbackLocale: window.LOCALE,
messages: window.localisation
})
const websocketPrefix =
window.location.protocol === 'http:' ? 'ws://' : 'wss://'
const websocketUrl = `${websocketPrefix}${window.location.host}/api/v1/ws`
window.g = Vue.reactive({
offline: !navigator.onLine,
visibleDrawer: false,
@@ -39,9 +9,16 @@ window.g = Vue.reactive({
fiatTracking: false,
wallets: [],
payments: [],
langs: [],
walletEventListeners: [],
updatePayments: false,
updatePaymentsHash: '',
walletFlip: Quasar.LocalStorage.getItem('lnbits.walletFlip') ?? false
walletFlip: Quasar.LocalStorage.getItem('lnbits.walletFlip') ?? false,
locale:
Quasar.LocalStorage.getItem('lnbits.lang') ?? navigator.languages[1] ?? 'en'
})
window.dateFormat = 'YYYY-MM-DD HH:mm'
const websocketPrefix =
window.location.protocol === 'http:' ? 'ws://' : 'wss://'
const websocketUrl = `${websocketPrefix}${window.location.host}/api/v1/ws`
+8
View File
@@ -225,7 +225,15 @@ window.app.use(Quasar, {
}
}
})
window.i18n = new VueI18n.createI18n({
locale: window.g.locale,
fallbackLocale: 'en',
messages: window.localisation
})
window.app.use(window.i18n)
window.app.provide('g', g)
window.app.use(window.router)
window.app.component('DynamicComponent', DynamicComponent)
+2 -2
View File
@@ -168,7 +168,7 @@ window.PagePayments = {
p.timeFrom = moment.utc(p.created_at).local().fromNow()
p.outgoing = p.amount < 0
p.amount =
new Intl.NumberFormat(window.LOCALE).format(p.amount / 1000) +
new Intl.NumberFormat(this.g.locale).format(p.amount / 1000) +
' sats'
if (p.extra?.wallet_fiat_amount) {
p.amountFiat = this.formatCurrency(
@@ -180,7 +180,7 @@ window.PagePayments = {
p.internal_memo = p.extra.internal_memo
}
p.fee_sats =
new Intl.NumberFormat(window.LOCALE).format(p.fee / 1000) + ' sats'
new Intl.NumberFormat(this.g.locale).format(p.fee / 1000) + ' sats'
return p
})
+2 -2
View File
@@ -41,13 +41,13 @@ window._lnbitsUtils = {
return Quasar.date.formatDate(new Date(isoDateString), window.dateFormat)
},
formatCurrency(value, currency) {
return new Intl.NumberFormat(window.LOCALE, {
return new Intl.NumberFormat(window.i18n.global.locale, {
style: 'currency',
currency: currency || 'sat'
}).format(value)
},
formatSat(value) {
return new Intl.NumberFormat(window.LOCALE).format(value)
return new Intl.NumberFormat(window.i18n.global.locale).format(value)
},
formatMsat(value) {
return this.formatSat(value / 1000)
-8
View File
@@ -283,14 +283,6 @@ window.windowMixin = {
}
this.applyBackgroundImage()
let locale = this.$q.localStorage.getItem('lnbits.lang')
if (locale) {
window.LOCALE = locale
window.i18n.global.locale = locale
}
this.g.langs = window.langs ?? []
addEventListener('offline', event => {
console.log('offline', event)
this.g.offline = true
+1
View File
@@ -75,6 +75,7 @@
"js/components/lnbits-header.js",
"js/components/lnbits-drawer.js",
"js/components/lnbits-manage-extension-list.js",
"js/components/lnbits-language-dropdown.js",
"js/components/extension-settings.js",
"js/components/data-fields.js",
"js/components/payment-list.js",
+2 -1
View File
@@ -15,7 +15,8 @@ include('components/lnbits-footer.vue') %} {%
include('components/lnbits-header.vue') %} {%
include('components/lnbits-drawer.vue') %} {%
include('components/lnbits-home-logos.vue') %} {%
include('components/lnbits-manage-extension-list.vue') %}
include('components/lnbits-manage-extension-list.vue') %} {%
include('components/lnbits-language-dropdown.vue') %}
<template id="lnbits-wallet-list">
<q-list
@@ -70,6 +70,8 @@
<span>OFFLINE</span>
</q-badge>
<lnbits-language-dropdown></lnbits-language-dropdown>
<q-btn-dropdown
v-if="g.user || isUserAuthorized"
flat
@@ -0,0 +1,19 @@
<template id="lnbits-language-dropdown">
<q-btn-dropdown dense flat rounded size="sm" icon="language" class="q-pl-md">
<q-list v-for="(lang, index) in langs" :key="index">
<q-item
clickable
v-close-popup
:active="activeLanguage(lang.value)"
@click="changeLanguage(lang.value)"
>
<q-item-section>
<q-item-label
v-text="lang.display ?? lang.value.toUpperCase()"
></q-item-label>
<q-tooltip><span v-text="lang.label"></span></q-tooltip>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
</template>
+1 -27
View File
@@ -366,33 +366,7 @@
<span v-text="$t('language')"></span>
</div>
<div class="col-8">
<q-btn-dropdown
dense
flat
round
size="sm"
icon="language"
class="q-pl-md"
>
<q-list v-for="(lang, index) in g.langs" :key="index">
<q-item
clickable
v-close-popup
:active="activeLanguage(lang.value)"
@click="changeLanguage(lang.value)"
><q-item-section>
<q-item-label
v-text="
lang.display ?? lang.value.toUpperCase()
"
></q-item-label>
<q-tooltip
><span v-text="lang.label"></span
></q-tooltip>
</q-item-section>
</q-item>
</q-list>
</q-btn-dropdown>
<lnbits-language-dropdown />
</div>
</div>
<div class="row q-mb-md">
+1
View File
@@ -127,6 +127,7 @@
"js/components/lnbits-header.js",
"js/components/lnbits-drawer.js",
"js/components/lnbits-manage-extension-list.js",
"js/components/lnbits-language-dropdown.js",
"js/components/extension-settings.js",
"js/components/data-fields.js",
"js/components/payment-list.js",