diff --git a/src/containers/BudgetDetails/BudgetDetails.css b/src/containers/BudgetDetails/BudgetDetails.css
index 8949c2f..d05937b 100644
--- a/src/containers/BudgetDetails/BudgetDetails.css
+++ b/src/containers/BudgetDetails/BudgetDetails.css
@@ -30,12 +30,17 @@
opacity: 0;
}
-.budget-details__counters {
+.budget-details__counters,
+.budget-details__title {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
+.budget-details__title {
+ margin: 0.25rem;
+}
+
.budget-details__counter-wrapper {
display: flex;
flex-direction: column;
@@ -80,8 +85,24 @@
margin: 0 auto;
}
-.budget-details__participants {
+.budget-details__aside .tabs {
flex-grow: 1;
+ margin-bottom: 0;
+ width: 100%;
+}
+.budget-details__aside .tabs label {
+ align-self: baseline;
+}
+.budget-details__aside .content {
+ align-self: flex-start;
+ height: 100%;
+}
+
+.budget-details__tab-content-wrapper {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ height: calc(100% - 2.75rem);
}
#budget-details #send-invite {
@@ -95,6 +116,11 @@
display: none;
}
+.budget-details__actions--isopen {
+ justify-content: center;
+ display: none;
+}
+
.budget-details__actions--visible {
display: flex;
}
diff --git a/src/containers/BudgetDetails/BudgetDetails.mjs b/src/containers/BudgetDetails/BudgetDetails.mjs
index edd6ace..1a351c8 100644
--- a/src/containers/BudgetDetails/BudgetDetails.mjs
+++ b/src/containers/BudgetDetails/BudgetDetails.mjs
@@ -11,6 +11,7 @@ import { Alert } from "../Alert/Alert.mjs";
import { ParticipantsList } from "../ParticipantsList/ParticipantsList.mjs";
import { FeatureDetector } from "../../core/FeatureDetector.mjs";
import { Router } from '../../core/Router.mjs'
+import { BudgetSettings } from "./components/Settings/BudgetSettings.mjs";
importStyle('/src/containers/BudgetDetails/BudgetDetails.css')
@@ -18,6 +19,7 @@ const template = document.querySelector('template#budget-details-template')
const Api = new RequestManager('budget')
const transactionsController = new TransactionsList()
const participantsController = new ParticipantsList()
+const settingsController = new BudgetSettings()
const isMobile = FeatureDetector.isMobile
@@ -46,11 +48,11 @@ export class BudgetDetails extends AnimatedComponent {
transactionsController.data = mapArrayToObjectId(this.data?.transactions ?? [])
participantsController.data = mapArrayToObjectId(this.data?.participants ?? [], ({ userId }) => userId)
const data = await Api.get('details', `budgets/${id}`)
- this.data = data
+ this.data = data
transactionsController.data = mapArrayToObjectId(data?.transactions ?? [])
participantsController.data = mapArrayToObjectId(data?.participants ?? [], ({ userId }) => userId)
- if (this.data?.participants.length === 1 && Router.queryParams.has('fresh')) { // only the owner
+ if (this.data?.participants?.length === 1 && Router.queryParams.has('fresh')) { // only the owner
this.showInviteDialog()
}
}
@@ -96,8 +98,9 @@ export class BudgetDetails extends AnimatedComponent {
const container = template.content.cloneNode(true)
this.update(container)
parent.appendChild(container)
- transactionsController.renderTo(this.getContainer()?.querySelector('.budget-details__transactions'))
- participantsController.renderTo(this.getContainer()?.querySelector('.budget-details__participants'))
+ transactionsController.renderTo(this.getContainer()?.querySelector(`.${this.getCssClass('transactions')}`))
+ participantsController.renderTo(this.getContainer()?.querySelector(`.${this.getCssClass('participants')}`))
+ settingsController.renderTo(this.getContainer()?.querySelector(`.${this.getCssClass('settings')}`))
}
update = (target) => {
@@ -117,12 +120,17 @@ export class BudgetDetails extends AnimatedComponent {
this.addCssClassConditionally(
!allowedUserStatuses.includes(this.data?.currentUserStatus),
'hidden',
- container.querySelector('#participants-list-btn')
+ container.querySelector('#settings-btn')
)
}
const { myBalance, totalBalance } = getBudgetBalanceFromTransactions(this.data.transactions, this.data.participants)
- this.setAttr(container, `.${this.getCssClass('counter', 'my')}`, 'textContent', currencyFormatters.get(this.data.currency)?.format(Math.abs(myBalance)))
+ this.setAttr(container, `.${this.getCssClass('counter', 'my')}`, 'textContent', currencyFormatters.get(this.data.currency)?.format(Math.abs(myBalance)))
+ this.addCssClassConditionally(
+ !allowedUserStatuses.includes(this.data?.currentUserStatus) && this.data?.type === 'open',
+ 'hidden',
+ container.querySelector(`.${this.getCssClass('counter', 'my')}`).parentElement
+ )
this.addCssClassConditionally(
myBalance > 0,
this.getCssClass('counter', 'positive'),
@@ -134,7 +142,13 @@ export class BudgetDetails extends AnimatedComponent {
container.querySelector(`.${this.getCssClass('counter', 'my')}`)
)
this.setAttr(container, `.${this.getCssClass('counter', 'total')}`, 'textContent', currencyFormatters.get(this.data.currency)?.format(totalBalance))
+ this.setAttr(container, `.${this.getCssClass('title')}`, 'textContent', this.data.name)
+ this.addCssClassConditionally(
+ !allowedUserStatuses.includes(this.data?.currentUserStatus) && this.data?.type === 'open',
+ this.getCssClass('actions', 'visible'),
+ container.querySelector(`.${this.getCssClass('actions', 'isopen')}`)
+ )
this.addCssClassConditionally(
this.data?.currentUserStatus === PARTICIPANT_STATUSES.INVITED,
this.getCssClass('actions', 'visible'),
@@ -222,7 +236,7 @@ export class BudgetDetails extends AnimatedComponent {
}
}
- onShowParticipants = (e) => {
+ onShowSettings = (e) => {
e.stopPropagation()
this.addCssClassConditionally(
isMobile,
@@ -231,7 +245,7 @@ export class BudgetDetails extends AnimatedComponent {
)
}
- onHideParticipants = (e) => {
+ onHideSettings = (e) => {
e.stopPropagation()
this.getContainer()?.querySelector(`.${this.getCssClass('aside')}`)?.classList.remove(
this.getCssClass('aside', 'visible')
@@ -260,14 +274,14 @@ export class BudgetDetails extends AnimatedComponent {
handler: this.showInviteDialog,
},
{
- selector: '#participants-list-btn',
+ selector: '#settings-btn',
event: 'click',
- handler: this.onShowParticipants,
+ handler: this.onShowSettings,
},
{
- selector: '#participants-list-close-btn',
+ selector: '#settings-close-btn',
event: 'click',
- handler: this.onHideParticipants,
+ handler: this.onHideSettings,
},
])
}
diff --git a/src/containers/BudgetDetails/components/Settings/BudgetSettings.css b/src/containers/BudgetDetails/components/Settings/BudgetSettings.css
new file mode 100644
index 0000000..7580a7a
--- /dev/null
+++ b/src/containers/BudgetDetails/components/Settings/BudgetSettings.css
@@ -0,0 +1,28 @@
+.budget-settings {
+ min-height: calc(100% - 2.75rem);
+ display: flex;
+ flex-direction: column;
+}
+.budget-settings input {
+ display: initial;
+}
+.budget-settings input:checked + label {
+ border-bottom: 0;
+}
+.budget-settings label {
+ font-size: inherit;
+ font-weight: initial;
+ color: initial;
+ padding: 0;
+ flex-grow: 1;
+ text-align: left;
+}
+html[dir=rtl] .budget-settings label {
+ text-align: right;
+}
+.budget-settings__fields {
+ flex-grow: 1;
+}
+.budget-settings__save-btn {
+ width: 100%;
+}
diff --git a/src/containers/BudgetDetails/components/Settings/BudgetSettings.mjs b/src/containers/BudgetDetails/components/Settings/BudgetSettings.mjs
new file mode 100644
index 0000000..856fa37
--- /dev/null
+++ b/src/containers/BudgetDetails/components/Settings/BudgetSettings.mjs
@@ -0,0 +1,132 @@
+// @ts-check
+import { AuthManager } from '../../../../core/AuthManager.mjs'
+import { Component } from '../../../../core/Component.mjs'
+import { RequestManager } from '../../../../core/RequestManager.mjs'
+import { Store } from '../../../../core/Store.mjs'
+import { importStyle } from '../../../../utils/imports.js'
+
+importStyle('/src/containers/BudgetDetails/components/Settings/BudgetSettings.css')
+
+const template = document.querySelector('template#budget-settings-template')
+
+const Api = new RequestManager('budget-settings')
+
+export class BudgetSettings extends Component {
+ containerId = 'budget-settings'
+ id
+ budgetId
+ #isDirty = false
+ #state = new Map([
+ ['opened', false]
+ ])
+
+ set isDirty(val) {
+ if (!val) {
+ this.setAttr(this.getContainer(), `.${this.getCssClass('save-btn')}`, 'disabled', 'disabled')
+ } else {
+ this.getContainer()?.querySelector(`.${this.getCssClass('save-btn')}`)?.removeAttribute('disabled')
+ }
+
+ this.#isDirty = val
+ }
+
+ constructor() {
+ super()
+ if (!template) {
+ throw new Error('#budget-settings-template must be present in the HTML!')
+ }
+ this.budgetId = Store.get('selectedBudgetId')
+ Store.subscribe('selectedBudgetId', this.onSelectBudget)
+ }
+
+ renderTo(container) {
+ //@ts-ignore
+ const content = template.content.cloneNode(true)
+ container.appendChild(content)
+ Store.subscribe('selectedBudgetId', this.update)
+ Store.subscribe('budgets', this.onSelectBudget)
+ }
+
+ async exterminate() {
+ Store.unsubscribe('selectedBudgetId', this.update)
+ Store.unsubscribe('budgets', this.onSelectBudget)
+ await super.exterminate()
+ }
+
+ onSelectBudget = () => {
+ const newId = Store.get('selectedBudgetId')
+ Store.unsubscribe('selectedBudgetId', this.update)
+ Store.subscribe(`budgets.${newId}`, this.update)
+ this.budgetId = newId
+ this.update()
+ }
+
+ update = () => {
+ const budget = Store.get(`budgets.${this.budgetId}`)
+ if (!budget) {
+ return
+ }
+ this.stopListeners()
+ if (budget.userId === AuthManager.data.id) {
+ this.attachListeners()
+ }
+ this.getContainer()?.reset()
+ this.#state = new Map([
+ ['opened', budget.type === 'open'],
+ ])
+ if (this.#state.get('opened')) {
+ this.setAttr(this.getContainer(), 'input[name="opened"]', 'checked', 'checked')
+ } else {
+ this.getContainer()?.querySelector('input[name="opened"]')?.removeAttribute('checked')
+ }
+ this.isDirty = false
+ }
+
+ #handleChange = (e) => {
+ const fieldName = e.target.getAttribute('name')
+ const value = e.target.checked
+ this.isDirty = this.#state.get(fieldName) !== value
+ }
+
+ #handleSave = async (e) => {
+ e.preventDefault()
+ if (!this.#isDirty || this.isInProgress) {
+ return
+ }
+ this.isInProgress = true
+ const oldState = new Map([ ...this.#state.entries() ])
+ try {
+ const fd = new FormData(this.getContainer())
+ this.#state.forEach((value, key) => {
+ if (fd.has(key)) {
+ this.#state.set(key, fd.get(key))
+ } else {
+ this.#state.set(key, false)
+ }
+ })
+ this.isDirty = false
+ await Api.post('save', `budgets/${this.budgetId}/settings`, { body: fd })
+ } catch (er) {
+ const { Alert } = await import('../../../Alert/Alert.mjs')
+ new Alert('danger', er)
+ this.#state = oldState
+ this.isDirty = true
+ } finally {
+ this.isInProgress = false
+ Store.set(`budgets.${this.budgetId}.type`, this.#state.get('opened') ? 'open' : 'private')
+ }
+ }
+
+ listeners = new Set([
+ {
+ selector: '.budget-settings__save-btn',
+ event: 'click',
+ handler: this.#handleSave,
+ },
+ {
+ selector: 'input',
+ event: 'change',
+ handler: this.#handleChange,
+ }
+ ])
+}
diff --git a/src/containers/NewBudget/NewBudget.css b/src/containers/NewBudget/NewBudget.css
index 14317cc..4e5aa08 100644
--- a/src/containers/NewBudget/NewBudget.css
+++ b/src/containers/NewBudget/NewBudget.css
@@ -3,7 +3,7 @@
flex-direction: column;
justify-content: space-between;
height: 100%;
- min-width: 300px;
+ max-width: 300px;
}
.new-budget__fields {
display: flex;
@@ -18,14 +18,17 @@
.new-budget__buttons button {
width: 45%;
}
-.new-budget__fields strong {
- display: inline-block;
- margin: 1rem 0 0.25rem;
+.new-budget__fields h4 {
+ margin-block-end: 0.5rem;
}
-.new-budget__suggested-participants-item {
+.new-budget__fields h6 {
+ margin: -0.5rem 0 1rem;
+}
+.new-budget__field--checkbox {
display: flex;
justify-content: space-between;
}
-.new-budget__suggested-participants-item label {
+.new-budget__field--checkbox label {
flex-grow: 1;
+ margin: 0 1rem;
}
diff --git a/src/containers/NewBudget/NewBudget.mjs b/src/containers/NewBudget/NewBudget.mjs
index 20c90ee..2f8f9cc 100644
--- a/src/containers/NewBudget/NewBudget.mjs
+++ b/src/containers/NewBudget/NewBudget.mjs
@@ -80,6 +80,7 @@ export class NewBudget extends Component {
name,
userId: AuthManager.data.id,
transactions: [],
+ type: data.get('isOpen') ? 'open' : 'private',
participants: [{
id: AuthManager.data.id,
status: PARTICIPANT_STATUSES.OWNER,
diff --git a/src/core/RequestManager.mjs b/src/core/RequestManager.mjs
index c005034..ece5fca 100644
--- a/src/core/RequestManager.mjs
+++ b/src/core/RequestManager.mjs
@@ -47,6 +47,9 @@ export class RequestManager {
AuthManager.isLoggedIn = false
}
if (response.status >= 300) {
+ if (response.status === 404) {
+ throw new Error('Can\'t find that request...')
+ }
throw new Error((await response.json()).error)
} else {
return await response.json()
diff --git a/src/core/SettingsManager.mjs b/src/core/SettingsManager.mjs
index f505c98..3748e57 100644
--- a/src/core/SettingsManager.mjs
+++ b/src/core/SettingsManager.mjs
@@ -5,7 +5,7 @@ import { getFromLs, updateCurrencyFormatters } from "../utils/utils.mjs"
const darkThemeMedia = matchMedia('(prefers-color-scheme: dark)')
class CSettingsManager {
- #appVersion = '0.2.1'
+ #appVersion = '0.2.2'
#animationsEnabled = true
#autoLoginEnabled = getFromLs('autoLoginEnabled', 'true') === 'true'
#theme = getFromLs('theme', 'system')
diff --git a/styles/App.css b/styles/App.css
index af27718..355fef7 100644
--- a/styles/App.css
+++ b/styles/App.css
@@ -8,6 +8,10 @@ html {
margin: 0;
}
+h1, h2, h3, h4, h5, h6 {
+ font-family: "Patrick Hand SC", Neucha, sans-serif;;
+}
+
html.dark {
background-color: #41403e;
color: beige;
diff --git a/translations/ar.json b/translations/ar.json
index 993f7f9..273b5fb 100644
--- a/translations/ar.json
+++ b/translations/ar.json
@@ -114,10 +114,10 @@
"prop": "text",
"defaultValue": "Back"
},
- "participants-list-button": {
- "value": "مشاركون",
+ "settings-button": {
+ "value": "الإعدادات",
"prop": "text",
- "defaultValue": "Participants"
+ "defaultValue": "Settings"
},
"budget-details-my-balance": {
"value": "رصيدي",
@@ -144,6 +144,11 @@
"prop": "text",
"defaultValue": "Decline"
},
+ "budget-details-actions-open-notification": {
+ "value": "هذه الميزانية مفتوحة. سيتم الموافقة على طلبك تلقائيا.",
+ "prop": "text",
+ "defaultValue": "This budget is open. Your request will be automatically approved."
+ },
"budget-details-actions-ask": {
"value": "يمكنك طلب دعوة",
"prop": "text",
@@ -164,11 +169,36 @@
"prop": "text",
"defaultValue": "Close"
},
+ "participants-list-button": {
+ "value": "مشاركون",
+ "prop": "text",
+ "defaultValue": "Participants"
+ },
+ "settings-btn": {
+ "value": "الإعدادات",
+ "prop": "text",
+ "defaultValue": "Settings"
+ },
"budget-details-add-people": {
"value": "أضف أشخاصا",
"prop": "text",
"defaultValue": "Add people"
},
+ "budget-details-settings-open": {
+ "value": "الميزانية المفتوحة",
+ "prop": "text",
+ "defaultValue": "Open"
+ },
+ "budget-settings-isOpen": {
+ "value": "في الميزانيات المفتوحة ، تتم الموافقة على طلبات المشاركة تلقائيا.",
+ "prop": "text",
+ "defaultValue": "In open budgets participation requests are being approved automatically."
+ },
+ "budget-settings-save-btn": {
+ "value": "حفظ",
+ "prop": "text",
+ "defaultValue": "Save"
+ },
"transactions-list-ok": {
"value": "نعم",
"prop": "text",
@@ -221,8 +251,8 @@
},
"new-budget-title": {
"value": "عنوان الميزانية الجديد",
- "prop": "text",
- "defaultValue": ""
+ "prop": "placeholder",
+ "defaultValue": "New budget title"
},
"new-budget-currency": {
"value": "اختر العملة",
@@ -264,6 +294,21 @@
"prop": "text",
"defaultValue": "Suggested participants"
},
+ "new-budget-type": {
+ "value": "نوع الميزانية",
+ "prop": "text",
+ "defaultValue": "Budget type"
+ },
+ "new-budget-is-open-notice": {
+ "value": "إذا قمت بتشغيل هذا الإعداد ، فستتم الموافقة تلقائيا على أي طلبات مشاركة.",
+ "prop": "text",
+ "defaultValue": "If you turn this setting on, any participation requests will be automatically approved."
+ },
+ "new-budget-is-open": {
+ "value": "اجعل هذه الميزانية مفتوحة",
+ "prop": "text",
+ "defaultValue": "Make this budget open"
+ },
"new-budget-go": {
"value": "يخلق",
"prop": "text",
diff --git a/translations/bn.json b/translations/bn.json
index e67aded..2d8f9a2 100644
--- a/translations/bn.json
+++ b/translations/bn.json
@@ -114,10 +114,10 @@
"prop": "text",
"defaultValue": "Back"
},
- "participants-list-button": {
- "value": "অংশগ্রহণকারী",
+ "settings-button": {
+ "value": "সেটিংস",
"prop": "text",
- "defaultValue": "Participants"
+ "defaultValue": "Settings"
},
"budget-details-my-balance": {
"value": "আমার ভারসাম্য",
@@ -144,6 +144,11 @@
"prop": "text",
"defaultValue": "Decline"
},
+ "budget-details-actions-open-notification": {
+ "value": "এই বাজেট উন্মুক্ত আপনার অনুরোধ স্বয়ংক্রিয়ভাবে অনুমোদিত হবে.",
+ "prop": "text",
+ "defaultValue": "This budget is open. Your request will be automatically approved."
+ },
"budget-details-actions-ask": {
"value": "আপনি আমন্ত্রণ জন্য জিজ্ঞাসা করতে পারেন",
"prop": "text",
@@ -164,11 +169,36 @@
"prop": "text",
"defaultValue": "Close"
},
+ "participants-list-button": {
+ "value": "অংশগ্রহণকারী",
+ "prop": "text",
+ "defaultValue": "Participants"
+ },
+ "settings-btn": {
+ "value": "সেটিংস",
+ "prop": "text",
+ "defaultValue": "Settings"
+ },
"budget-details-add-people": {
"value": "মানুষ যোগ করুন",
"prop": "text",
"defaultValue": "Add people"
},
+ "budget-details-settings-open": {
+ "value": "উন্মুক্ত বাজেট",
+ "prop": "text",
+ "defaultValue": "Open"
+ },
+ "budget-settings-isOpen": {
+ "value": "খোলা বাজেটে অংশগ্রহণের অনুরোধ স্বয়ংক্রিয়ভাবে অনুমোদিত হচ্ছে.",
+ "prop": "text",
+ "defaultValue": "In open budgets participation requests are being approved automatically."
+ },
+ "budget-settings-save-btn": {
+ "value": "সংরক্ষণ",
+ "prop": "text",
+ "defaultValue": "Save"
+ },
"transactions-list-ok": {
"value": "ঠিক আছে",
"prop": "text",
@@ -221,8 +251,8 @@
},
"new-budget-title": {
"value": "নতুন বাজেট শিরোনাম",
- "prop": "text",
- "defaultValue": ""
+ "prop": "placeholder",
+ "defaultValue": "New budget title"
},
"new-budget-currency": {
"value": "মুদ্রা নির্বাচন করুন",
@@ -264,6 +294,21 @@
"prop": "text",
"defaultValue": "Suggested participants"
},
+ "new-budget-type": {
+ "value": "বাজেটের ধরন",
+ "prop": "text",
+ "defaultValue": "Budget type"
+ },
+ "new-budget-is-open-notice": {
+ "value": "আপনি এই সেটিং চালু হলে, কোনো অংশগ্রহণ অনুরোধ স্বয়ংক্রিয়ভাবে অনুমোদিত হবে.",
+ "prop": "text",
+ "defaultValue": "If you turn this setting on, any participation requests will be automatically approved."
+ },
+ "new-budget-is-open": {
+ "value": "এই বাজেটটি খুলুন",
+ "prop": "text",
+ "defaultValue": "Make this budget open"
+ },
"new-budget-go": {
"value": "যাও",
"prop": "text",
diff --git a/translations/en.json b/translations/en.json
index 43332ee..04ddf09 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -1 +1 @@
-{"page-title":{"value":"Rosplata","prop":"text","defaultValue":"Rosplata"},"description":{"value":"Rosplata הוא מנהל כספים שיתופי המארח במקור פתוח. צור תקציבים, שתף אותם עם חברים ופצל בקלות את החשבונות","prop":"content","defaultValue":"Rosplata is an opensource self hosted collaborative finance manager. Create budgets, share them with friends and easily split the bills"},"keywords":{"value":"מקור פתוח, שיתופי, מימון, תקציב, פיצול, הצעת חוק","prop":"content","defaultValue":"opensource, collaborative, finance, budget, split, bill"},"feature-checkup-title":{"value":"הדפדפן שלך חייב לתמוך בתכונות אלו","prop":"text","defaultValue":"Your browser must support these features"},"feature-checkup-description":{"value":"מצטער על אי הנוחות. נסה לפתוח את האפליקציה הזו בכרום או ב-Edge.","prop":"text","defaultValue":"Sorry for inconvenience. Try opening this app in Chrome or Edge."},"settings-item-app-version":{"value":"גרסת האפליקציה","prop":"text","defaultValue":"App version"},"settings-item-autologin":{"value":"כניסה אוטומטית","prop":"text","defaultValue":"Autologin"},"settings-item-theme":{"value":"נושא צבע","prop":"text","defaultValue":"Theme"},"settings-item-theme-system":{"value":"נושא המערכת","prop":"text","defaultValue":"System"},"settings-item-theme-light":{"value":"נושא קליל","prop":"text","defaultValue":"Light"},"settings-item-theme-dark":{"value":"ערכת נושא כהה","prop":"text","defaultValue":"Dark"},"settings-item-language":{"value":"שפה","prop":"text","defaultValue":"Language"},"settings-item-language-system":{"value":"תן לדפדפן להחליט","prop":"text","defaultValue":"Let browser decide"},"settings-item-language-ru":{"value":"Русский","prop":"text","defaultValue":"Russian"},"settings-item-language-en":{"value":"English","prop":"text","defaultValue":"English"},"settings-item-language-hi":{"value":"हिन्दी","prop":"text","defaultValue":"Hindi"},"settings-item-language-bn":{"value":"বাংলা","prop":"text","defaultValue":"Bengali"},"settings-item-language-zn":{"value":"中文","prop":"text","defaultValue":"Chinese"},"settings-item-language-ar":{"value":"العربية","prop":"text","defaultValue":"Arabic"},"settings-item-language-ko":{"value":"한국어","prop":"text","defaultValue":"Korean"},"settings-item-language-he":{"value":"עברית","prop":"text","defaultValue":"Hebrew"},"budgets-list-new":{"value":"צור תקציב חדש","prop":"text","defaultValue":"Create new"},"back":{"value":"תחזור","prop":"text","defaultValue":"Back"},"participants-list-button":{"value":"משתתפים","prop":"text","defaultValue":"Participants"},"budget-details-my-balance":{"value":"האיזון שלי","prop":"text","defaultValue":"My balance"},"budget-details-total-sum":{"value":"סכום כולל","prop":"text","defaultValue":"Total sum"},"budget-details-actions-invite":{"value":"אתם מוזמנים להשתתף","prop":"text","defaultValue":"You are invited to participate"},"budget-details-actions-accept":{"value":"לְקַבֵּל","prop":"text","defaultValue":"Accept"},"budget-details-actions-decline":{"value":"יְרִידָה","prop":"text","defaultValue":"Decline"},"budget-details-actions-ask":{"value":"אתה יכול לבקש הזמנה","prop":"text","defaultValue":"You can ask for invite"},"budget-details-actions-send-request":{"value":"שלח בקשה","prop":"text","defaultValue":"Send request"},"budget-details-actions-wait":{"value":"בעל התקציב צריך לאשר את בקשתך","prop":"text","defaultValue":"Budget owner have to approve your request"},"close":{"value":"לִסְגוֹר","prop":"text","defaultValue":"Close"},"budget-details-add-people":{"value":"הוסף אנשים","prop":"text","defaultValue":"Add people"},"transactions-list-ok":{"value":"בסדר","prop":"text","defaultValue":"mkay"},"transactions-list-comment":{"value":"הוסף הערה אופציונלית","prop":"placeholder","defaultValue":"Add optional comment"},"feature-detector-title":{"value":"מאפיינים","prop":"text","defaultValue":"Features"},"feature-detector-description":{"value":"תכונות שצריך לתמוך כדי שהאפליקציה הזו תעבוד","prop":"text","defaultValue":"That need to be supported for this app to work"},"menu-budgets":{"value":"תקציבים","prop":"text","defaultValue":"Budgets"},"menu-settings":{"value":"הגדרות","prop":"text","defaultValue":"Settings"},"menu-logout":{"value":"התנתק","prop":"text","defaultValue":"Log out"},"layout-login-title":{"value":"היכנס לרוספלטה","prop":"text","defaultValue":"Enter Rosplata"},"layout-login-description":{"value":"היכנס עם חשבון Google שלך כדי להתחיל להשתמש בתקציבים משותפים","prop":"text","defaultValue":"Sign in with your google account to start using shared budgets"},"layout-login-enter":{"value":"להיכנס","prop":"text","defaultValue":"Enter"},"new-budget-title":{"value":"כותרת תקציב חדשה","prop":"text","defaultValue":""},"new-budget-currency":{"value":"תבחר מדינה","prop":"text","defaultValue":"Select currency"},"currency-rub":{"value":"רובל רוסי","prop":"text","defaultValue":"Russian Rouble"},"currency-inr":{"value":"רופי הודי","prop":"text","defaultValue":"Indian Rupee"},"currency-usd":{"value":"דולר אמריקאי","prop":"text","defaultValue":"US Dollar"},"currency-eur":{"value":"יוֹרוֹ","prop":"text","defaultValue":"Euro"},"currency-cny":{"value":"יואן סיני","prop":"text","defaultValue":"Chinese Yuan"},"currency-jrd":{"value":"דינר ירדני","prop":"text","defaultValue":"Jordanian Dinar"},"new-budget-suggested-participants":{"value":"","prop":"text","defaultValue":"Suggested participants"},"new-budget-go":{"value":"ללכת","prop":"text","defaultValue":"Go"},"new-budget-reset":{"value":"אִתחוּל","prop":"text","defaultValue":"Reset"},"participants-list-ban":{"value":"לֶאֱסוֹר","prop":"text","defaultValue":"Ban"},"participants-list-revert":{"value":"לַחֲזוֹר","prop":"text","defaultValue":"Revert"},"participants-list-approve":{"value":"לְאַשֵׁר","prop":"text","defaultValue":"Approve"},"invite-dialog-description":{"value":"סרוק את קוד ה-QR הזה כדי לפתוח את התקציב הזה במכשיר שלך.","prop":"text","defaultValue":"Scan this QR code to open this budget on your device."},"invite-dialog-share-link":{"value":"שתף קישור במקום זאת","prop":"text","defaultValue":"Share link instead"}}
\ No newline at end of file
+{"page-title":{"value":"Rosplata","prop":"text","defaultValue":"Rosplata"},"description":{"value":"Rosplata הוא מנהל כספים שיתופי המארח במקור פתוח. צור תקציבים, שתף אותם עם חברים ופצל בקלות את החשבונות","prop":"content","defaultValue":"Rosplata is an opensource self hosted collaborative finance manager. Create budgets, share them with friends and easily split the bills"},"keywords":{"value":"מקור פתוח, שיתופי, מימון, תקציב, פיצול, הצעת חוק","prop":"content","defaultValue":"opensource, collaborative, finance, budget, split, bill"},"feature-checkup-title":{"value":"הדפדפן שלך חייב לתמוך בתכונות אלו","prop":"text","defaultValue":"Your browser must support these features"},"feature-checkup-description":{"value":"מצטער על אי הנוחות. נסה לפתוח את האפליקציה הזו בכרום או ב-Edge.","prop":"text","defaultValue":"Sorry for inconvenience. Try opening this app in Chrome or Edge."},"settings-item-app-version":{"value":"גרסת האפליקציה","prop":"text","defaultValue":"App version"},"settings-item-autologin":{"value":"כניסה אוטומטית","prop":"text","defaultValue":"Autologin"},"settings-item-theme":{"value":"נושא צבע","prop":"text","defaultValue":"Theme"},"settings-item-theme-system":{"value":"נושא המערכת","prop":"text","defaultValue":"System"},"settings-item-theme-light":{"value":"נושא קליל","prop":"text","defaultValue":"Light"},"settings-item-theme-dark":{"value":"ערכת נושא כהה","prop":"text","defaultValue":"Dark"},"settings-item-language":{"value":"שפה","prop":"text","defaultValue":"Language"},"settings-item-language-system":{"value":"תן לדפדפן להחליט","prop":"text","defaultValue":"Let browser decide"},"settings-item-language-ru":{"value":"Русский","prop":"text","defaultValue":"Russian"},"settings-item-language-en":{"value":"English","prop":"text","defaultValue":"English"},"settings-item-language-hi":{"value":"हिन्दी","prop":"text","defaultValue":"Hindi"},"settings-item-language-bn":{"value":"বাংলা","prop":"text","defaultValue":"Bengali"},"settings-item-language-zn":{"value":"中文","prop":"text","defaultValue":"Chinese"},"settings-item-language-ar":{"value":"العربية","prop":"text","defaultValue":"Arabic"},"settings-item-language-ko":{"value":"한국어","prop":"text","defaultValue":"Korean"},"settings-item-language-he":{"value":"עברית","prop":"text","defaultValue":"Hebrew"},"budgets-list-new":{"value":"צור תקציב חדש","prop":"text","defaultValue":"Create new"},"back":{"value":"תחזור","prop":"text","defaultValue":"Back"},"settings-button":{"value":"","prop":"text","defaultValue":"Settings"},"budget-details-my-balance":{"value":"האיזון שלי","prop":"text","defaultValue":"My balance"},"budget-details-total-sum":{"value":"סכום כולל","prop":"text","defaultValue":"Total sum"},"budget-details-actions-invite":{"value":"אתם מוזמנים להשתתף","prop":"text","defaultValue":"You are invited to participate"},"budget-details-actions-accept":{"value":"לְקַבֵּל","prop":"text","defaultValue":"Accept"},"budget-details-actions-decline":{"value":"יְרִידָה","prop":"text","defaultValue":"Decline"},"budget-details-actions-open-notification":{"value":"","prop":"text","defaultValue":"This budget is open. Your request will be automatically approved."},"budget-details-actions-ask":{"value":"אתה יכול לבקש הזמנה","prop":"text","defaultValue":"You can ask for invite"},"budget-details-actions-send-request":{"value":"שלח בקשה","prop":"text","defaultValue":"Send request"},"budget-details-actions-wait":{"value":"בעל התקציב צריך לאשר את בקשתך","prop":"text","defaultValue":"Budget owner have to approve your request"},"close":{"value":"לִסְגוֹר","prop":"text","defaultValue":"Close"},"participants-list-button":{"value":"משתתפים","prop":"text","defaultValue":"Participants"},"settings-btn":{"value":"","prop":"text","defaultValue":"Settings"},"budget-details-add-people":{"value":"הוסף אנשים","prop":"text","defaultValue":"Add people"},"budget-details-settings-open":{"value":"","prop":"text","defaultValue":"Open"},"budget-settings-isOpen":{"value":"","prop":"text","defaultValue":"In open budgets participation requests are being approved automatically."},"budget-settings-save-btn":{"value":"","prop":"text","defaultValue":"Save"},"transactions-list-ok":{"value":"בסדר","prop":"text","defaultValue":"mkay"},"transactions-list-comment":{"value":"הוסף הערה אופציונלית","prop":"placeholder","defaultValue":"Add optional comment"},"feature-detector-title":{"value":"מאפיינים","prop":"text","defaultValue":"Features"},"feature-detector-description":{"value":"תכונות שצריך לתמוך כדי שהאפליקציה הזו תעבוד","prop":"text","defaultValue":"That need to be supported for this app to work"},"menu-budgets":{"value":"תקציבים","prop":"text","defaultValue":"Budgets"},"menu-settings":{"value":"הגדרות","prop":"text","defaultValue":"Settings"},"menu-logout":{"value":"התנתק","prop":"text","defaultValue":"Log out"},"layout-login-title":{"value":"היכנס לרוספלטה","prop":"text","defaultValue":"Enter Rosplata"},"layout-login-description":{"value":"היכנס עם חשבון Google שלך כדי להתחיל להשתמש בתקציבים משותפים","prop":"text","defaultValue":"Sign in with your google account to start using shared budgets"},"layout-login-enter":{"value":"להיכנס","prop":"text","defaultValue":"Enter"},"new-budget-title":{"value":"כותרת תקציב חדשה","prop":"text","defaultValue":""},"new-budget-currency":{"value":"תבחר מדינה","prop":"text","defaultValue":"Select currency"},"currency-rub":{"value":"רובל רוסי","prop":"text","defaultValue":"Russian Rouble"},"currency-inr":{"value":"רופי הודי","prop":"text","defaultValue":"Indian Rupee"},"currency-usd":{"value":"דולר אמריקאי","prop":"text","defaultValue":"US Dollar"},"currency-eur":{"value":"יוֹרוֹ","prop":"text","defaultValue":"Euro"},"currency-cny":{"value":"יואן סיני","prop":"text","defaultValue":"Chinese Yuan"},"currency-jrd":{"value":"דינר ירדני","prop":"text","defaultValue":"Jordanian Dinar"},"new-budget-suggested-participants":{"value":"","prop":"text","defaultValue":"Suggested participants"},"new-budget-type":{"value":"","prop":"text","defaultValue":"Budget type"},"new-budget-is-open-notice":{"value":"","prop":"text","defaultValue":"If you turn this setting on, any participation requests will be automatically approved."},"new-budget-is-open":{"value":"","prop":"text","defaultValue":"Make this budget open"},"new-budget-go":{"value":"ללכת","prop":"text","defaultValue":"Go"},"new-budget-reset":{"value":"אִתחוּל","prop":"text","defaultValue":"Reset"},"participants-list-ban":{"value":"לֶאֱסוֹר","prop":"text","defaultValue":"Ban"},"participants-list-revert":{"value":"לַחֲזוֹר","prop":"text","defaultValue":"Revert"},"participants-list-approve":{"value":"לְאַשֵׁר","prop":"text","defaultValue":"Approve"},"invite-dialog-description":{"value":"סרוק את קוד ה-QR הזה כדי לפתוח את התקציב הזה במכשיר שלך.","prop":"text","defaultValue":"Scan this QR code to open this budget on your device."},"invite-dialog-share-link":{"value":"שתף קישור במקום זאת","prop":"text","defaultValue":"Share link instead"}}
\ No newline at end of file
diff --git a/translations/generated/ar.html b/translations/generated/ar.html
index 9e74056..2172733 100644
--- a/translations/generated/ar.html
+++ b/translations/generated/ar.html
@@ -103,9 +103,10 @@
عُد