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.msat = data.balance_msat
newWallet.sat = Math.floor(data.balance_msat / 1000) 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 newWallet.sat
) )
if (newWallet.walletType === 'lightning-shared') { if (newWallet.walletType === 'lightning-shared') {
@@ -105,7 +105,9 @@ window.LNbits = {
obj.msat = obj.amount obj.msat = obj.amount
obj.sat = obj.msat / 1000 obj.sat = obj.msat / 1000
obj.tag = obj.extra?.tag 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.isIn = obj.amount > 0
obj.isOut = obj.amount < 0 obj.isOut = obj.amount < 0
obj.isPending = obj.status === 'pending' 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({ window.g = Vue.reactive({
offline: !navigator.onLine, offline: !navigator.onLine,
visibleDrawer: false, visibleDrawer: false,
@@ -39,9 +9,16 @@ window.g = Vue.reactive({
fiatTracking: false, fiatTracking: false,
wallets: [], wallets: [],
payments: [], payments: [],
langs: [],
walletEventListeners: [], walletEventListeners: [],
updatePayments: false, updatePayments: false,
updatePaymentsHash: '', 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.use(window.i18n)
window.app.provide('g', g) window.app.provide('g', g)
window.app.use(window.router) window.app.use(window.router)
window.app.component('DynamicComponent', DynamicComponent) 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.timeFrom = moment.utc(p.created_at).local().fromNow()
p.outgoing = p.amount < 0 p.outgoing = p.amount < 0
p.amount = p.amount =
new Intl.NumberFormat(window.LOCALE).format(p.amount / 1000) + new Intl.NumberFormat(this.g.locale).format(p.amount / 1000) +
' sats' ' sats'
if (p.extra?.wallet_fiat_amount) { if (p.extra?.wallet_fiat_amount) {
p.amountFiat = this.formatCurrency( p.amountFiat = this.formatCurrency(
@@ -180,7 +180,7 @@ window.PagePayments = {
p.internal_memo = p.extra.internal_memo p.internal_memo = p.extra.internal_memo
} }
p.fee_sats = 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 return p
}) })
+2 -2
View File
@@ -41,13 +41,13 @@ window._lnbitsUtils = {
return Quasar.date.formatDate(new Date(isoDateString), window.dateFormat) return Quasar.date.formatDate(new Date(isoDateString), window.dateFormat)
}, },
formatCurrency(value, currency) { formatCurrency(value, currency) {
return new Intl.NumberFormat(window.LOCALE, { return new Intl.NumberFormat(window.i18n.global.locale, {
style: 'currency', style: 'currency',
currency: currency || 'sat' currency: currency || 'sat'
}).format(value) }).format(value)
}, },
formatSat(value) { formatSat(value) {
return new Intl.NumberFormat(window.LOCALE).format(value) return new Intl.NumberFormat(window.i18n.global.locale).format(value)
}, },
formatMsat(value) { formatMsat(value) {
return this.formatSat(value / 1000) return this.formatSat(value / 1000)
-8
View File
@@ -283,14 +283,6 @@ window.windowMixin = {
} }
this.applyBackgroundImage() 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 => { addEventListener('offline', event => {
console.log('offline', event) console.log('offline', event)
this.g.offline = true this.g.offline = true
+1
View File
@@ -75,6 +75,7 @@
"js/components/lnbits-header.js", "js/components/lnbits-header.js",
"js/components/lnbits-drawer.js", "js/components/lnbits-drawer.js",
"js/components/lnbits-manage-extension-list.js", "js/components/lnbits-manage-extension-list.js",
"js/components/lnbits-language-dropdown.js",
"js/components/extension-settings.js", "js/components/extension-settings.js",
"js/components/data-fields.js", "js/components/data-fields.js",
"js/components/payment-list.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-header.vue') %} {%
include('components/lnbits-drawer.vue') %} {% include('components/lnbits-drawer.vue') %} {%
include('components/lnbits-home-logos.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"> <template id="lnbits-wallet-list">
<q-list <q-list
@@ -70,6 +70,8 @@
<span>OFFLINE</span> <span>OFFLINE</span>
</q-badge> </q-badge>
<lnbits-language-dropdown></lnbits-language-dropdown>
<q-btn-dropdown <q-btn-dropdown
v-if="g.user || isUserAuthorized" v-if="g.user || isUserAuthorized"
flat 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> <span v-text="$t('language')"></span>
</div> </div>
<div class="col-8"> <div class="col-8">
<q-btn-dropdown <lnbits-language-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>
</div> </div>
</div> </div>
<div class="row q-mb-md"> <div class="row q-mb-md">
+1
View File
@@ -127,6 +127,7 @@
"js/components/lnbits-header.js", "js/components/lnbits-header.js",
"js/components/lnbits-drawer.js", "js/components/lnbits-drawer.js",
"js/components/lnbits-manage-extension-list.js", "js/components/lnbits-manage-extension-list.js",
"js/components/lnbits-language-dropdown.js",
"js/components/extension-settings.js", "js/components/extension-settings.js",
"js/components/data-fields.js", "js/components/data-fields.js",
"js/components/payment-list.js", "js/components/payment-list.js",