gitscope
← marzneshin / Diff · 1c0d1b7 → 1c0d1b7
Changes 1c0d1b7..1c0d1b7
Patch commit
diff --git a/dashboard/biome.json b/dashboard/biome.json
new file mode 100644
index 0000000..0506472
--- /dev/null
+++ b/dashboard/biome.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://biomejs.dev/schemas/1.6.4/schema.json",
+ "formatter": {
+ "indentStyle": "space",
+ "indentSize": 2
+ },
+ "json": {
+ "formatter": {
+ "indentStyle": "space",
+ "indentSize": 2,
+ "indentWidth": 2
+ }
+ }
+}
diff --git a/dashboard/public/locales/en.json b/dashboard/public/locales/en.json
index d580870..17c5207 100644
--- a/dashboard/public/locales/en.json
+++ b/dashboard/public/locales/en.json
@@ -1,295 +1,300 @@
{
- "name": "Name",
- "status": "Status",
- "address": "Address",
- "users": "Users",
- "nodes": "Nodes",
- "services": "Services",
- "hosts": "Hosts",
- "username": "Username",
- "password": "Password",
- "inbounds": "Inbounds",
- "submit": "Submit",
- "login": "Login",
- "edit": "Edit",
- "actions": "Actions",
- "settings": "Settings",
- "logs": "Logs",
- "note": "Note",
- "config": "Config",
- "tag": "Tag",
- "protocol": "Protocol",
- "online": "Online",
- "offline": "Offline",
- "not_connected": "Not Connected",
- "apply": "Apply",
- "open": "Open",
- "delete": "Delete",
- "port": "Port",
- "create": "Create",
- "path": "Path",
- "host": "Host",
- "alpn": "ALPN",
- "security": "Security",
- "user_info": "Users Info",
- "subscription": "Subscription",
- "subscription_link": "Subscription Link",
- "fingerprint": "Fingerprint",
- "mux": "Mux",
- "fragment": "Fragment",
- "enable": "Enable",
- "disable": "Disable",
- "close": "Close",
- "save": "Save",
- "days": "Days",
- "home": "Home",
- "disabled": "Disabled",
- "advanced-options": "Advanced Options",
- "page": {
- "settings": {
- "certificate": {
- "copy": "Copy Certificate",
- "error": "Certificate Unavailable",
- "copied": "Certificate Copied"
- }
- },
- "login": {
- "username": {
- "error": {
- "isRequired": "Username is required"
- }
- },
- "password": {
- "error": {
- "is-required": "Password is required"
- }
- }
- },
- "nodes": {
- "settings": {
- "title": "Nodes Settings",
- "detail": "Details",
- "log-container": {
- "title": "Marznode Xray config logs"
- }
- },
- "dialogs": {
- "creation": {
- "title": "Nodes Creation"
- },
- "deletion": {
- "title": "Nodes Deletion"
- },
- "edition": {
- "title": "Nodes Edition"
- }
- },
- "usage_coefficient": "Usage Coefficient",
- "add_as_new_host": "Add as new hosts",
- "certificate-alert": {
- "title": "Nodes Certificate Configuration",
- "desc": "If you aim to configure your nodes certificate, checkout settings page.",
- "click": "Click Here"
- }
- },
- "services": {
- "settings": {
- "title": "Servicecs Settings",
- "detail": "Details"
- },
- "dialogs": {
- "creation": {
- "title": "Services Creation"
- },
- "deletion": {
- "title": "Services Deletion"
- },
- "edition": {
- "title": "Services Edition"
- }
- }
- },
- "users": {
- "data_limit": "Data Limit",
- "used_traffic": "Used Traffic",
- "data_limit_reset_strategy": "Data Limit Reset Strategy",
- "online_at": "Online At",
- "expire_date": "Expire Date",
- "unlimited": "Unlimited",
- "limited": "Limited",
- "data_limit_method": "Data limit type",
- "determined_expire": "Determined",
- "expire_method": "Expiration method",
- "onhold_expire": "On Hold",
- "reset_usage": "Reset Usage",
- "revoke_subscription": "Revoke Subscription",
- "on_hold_expire_duration": "On Hold",
- "on_hold_timeout": "On Hold Timeout",
- "settings": {
- "subscription_link": {
- "copied": "Subscription Link Copied",
- "copy": "Copy Subscription Link",
- "error": "Unable to copy Subscription Link"
- }
- },
- "services-alert": {
- "title": "No Service were found",
- "desc": "Make sure you create services to enable your users with inbounds to connect with.",
- "click": "Click Here"
- },
- "dialogs": {
- "edition": {
- "title": "Users Edition"
- },
- "creation": {
- "title": "Users Creation"
- },
- "deletion": {
- "title": "Users Deletion"
- },
- "mutation": {
- "note": {
- "desc": "Leave a note about your user"
- }
- }
- }
- },
- "hosts": {
- "fragment": {
- "interval": "Interval",
- "length": "Length",
- "packets": "Packets",
- "length-error": "Length can not exceed 32 char and must be number-number",
- "interval-error": "Interval can not exceed 32 char and must be number-number",
- "packets-error": "Packets can not exceed 32 char and must be number-number or be tlshello"
- },
- "popover-guide": {
- "title": "Using this setting, you are able to assign specific address for each inbound.",
- "desc": "Use these variables to make it dynamic",
- "username": "The username of the user",
- "dataUsage": "The current usage of the user",
- "remainingData": "Remaining data of the user",
- "dataLimit": "The usage limit of the user",
- "remainingDays": "Remaining days of the user",
- "expireDate": "Expiry date of the user",
- "jalaliExpireDate": "Expiry date of the user in solar calendar",
- "remainingTime": "Remaining time of the user",
- "statusEmoji": "User status as an emoji (✅,⌛,🪫,❌,🔌)",
- "proxyProtocol": "Proxy protocol (e.g. VMess)",
- "proxyMethod": "Proxy transport method (e.g. ws)",
- "currentServer": "Current server ip address",
- "security": "Security Layer",
- "host": "Request Host",
- "port": "Port",
- "path": "Path",
- "sni": "SNI",
- "advancedOptions": "Advanced options",
- "addHost": "Add host",
- "savedSuccess": "Hosts saved successfully",
- "loading": "loading...",
- "apply": "Apply",
- "port.info": "By default, a host uses the default port of the inbound. You can set a custom port in case this host is a server that forwards traffic from a port that differs from your server's port. For example, the server may forward traffic from port 8443 to the default port of your inbound server.",
- "path.info": "Set a path for host users, useful behind a reverse proxy.",
- "sni.info": "By default, a host uses the default SNI of the inbound. You can set a custom SNI in case this host is a server that has a different SNI. For example, the server may receive traffic with a different SSL certificate, perform SSL termination, and forward it to your inbound server.",
- "host.info": "By default, if a request host is set in the Xray config, this host is used. However, you can set a custom request host here if needed.",
- "security.info": "If the middleware server of this host uses a different security layer than the inbound's default, you can set a custom security layer here.",
- "alpn": "ALPN",
- "fingerprint": "Fingerprint",
- "host.multiHost": "To set multiple addresses, separate them with <badge>,</badge> Each time an address is chosen randomly.",
- "host.wildcard": "Use <badge>*</badge> to generate a random string (works for wildcard domain names)"
- },
- "mux": {
- "title": "Connection multiplexing",
- "desc": "Currently supported by v2rayng while using custom config"
- },
- "no-inbound-selection-alert": {
- "title": "No inbound is selected",
- "desc": "You must select an inbound inorder to create host."
- },
- "allowinsecure": "Allow insecure",
- "dialogs": {
- "edition": {
- "title": "Edit Host"
- },
- "creation": {
- "title": "Create Host"
- },
- "deletion": {
- "title": "Delete Host"
- },
- "mutation": {
- "allowinsecure": {
- "alert": "Due to security concerns, it is not recommended to allow Insecure"
- }
- }
- }
- }
- },
- "events": {
- "delete": {
- "error": "Failed to delete {{name}}",
- "success": {
- "title": "{{name}} is successfuly deleted",
- "desc": ""
- }
- },
- "create": {
- "error": "Failed to create {{name}}",
- "success": {
- "title": "{{name}} is successfuly created",
- "desc": ""
- }
- },
- "update": {
- "error": "Failed to update {{name}}",
- "success": {
- "title": "{{name}} is successfuly updated",
- "desc": ""
- }
- },
- "user_revoke": {
- "error": "Failed to revoke {{name}} subscription",
- "success": {
- "title": "{{name}} is successfuly created",
- "desc": ""
- }
- },
- "user_reset": {
- "error": "Failed to reset {{name}} data usage",
- "success": {
- "title": "{{name}} data usage is successfuly reseted",
- "desc": ""
- }
- },
- "user_status": {
- "error": "Failed to toggle {{name}} enable status",
- "success": {
- "title": "{{name}} enable status is successfuly updated",
- "desc": ""
- }
- }
- },
- "delete-confirmation": {
- "title": "Are you sure of this?",
- "desc": "This action cannot be undone. This will permanently delete your account and remove your data from our servers."
- },
- "table": {
- "row-per-page": "Rows per page",
- "no-result": "No results",
- "selected": "Selected",
- "toggle-column": "Toggle columns",
- "filter-placeholder": "Filter {{name}}"
- },
- "statuses": {
- "active": "Active",
- "connected": "Connected",
- "healthy": "Healthy",
- "disabled": "Disabled",
- "expired": "Expired",
- "on_hold": "On Hold",
- "connecting": "Connecting",
- "unhealthy": "Unhealthy",
- "limited": "Limited",
- "error": "Error"
- }
+ "name": "Name",
+ "status": "Status",
+ "address": "Address",
+ "users": "Users",
+ "nodes": "Nodes",
+ "services": "Services",
+ "hosts": "Hosts",
+ "username": "Username",
+ "password": "Password",
+ "inbounds": "Inbounds",
+ "submit": "Submit",
+ "login": "Login",
+ "edit": "Edit",
+ "actions": "Actions",
+ "settings": "Settings",
+ "logs": "Logs",
+ "note": "Note",
+ "config": "Config",
+ "tag": "Tag",
+ "protocol": "Protocol",
+ "online": "Online",
+ "offline": "Offline",
+ "not_connected": "Not Connected",
+ "apply": "Apply",
+ "open": "Open",
+ "delete": "Delete",
+ "port": "Port",
+ "create": "Create",
+ "path": "Path",
+ "host": "Host",
+ "alpn": "ALPN",
+ "security": "Security",
+ "user_info": "Users Info",
+ "subscription": "Subscription",
+ "subscription_link": "Subscription Link",
+ "fingerprint": "Fingerprint",
+ "mux": "Mux",
+ "fragment": "Fragment",
+ "enable": "Enable",
+ "disable": "Disable",
+ "close": "Close",
+ "save": "Save",
+ "days": "Days",
+ "home": "Home",
+ "cancel": "Cancel",
+ "dark": "Dark",
+ "light": "Light",
+ "system": "System",
+ "disabled": "Disabled",
+ "advanced-options": "Advanced Options",
+ "page": {
+ "settings": {
+ "certificate": {
+ "copy": "Copy Certificate",
+ "error": "Certificate Unavailable",
+ "copied": "Certificate Copied"
+ }
+ },
+ "login": {
+ "username": {
+ "error": {
+ "isRequired": "Username is required"
+ }
+ },
+ "password": {
+ "error": {
+ "is-required": "Password is required"
+ }
+ }
+ },
+ "nodes": {
+ "settings": {
+ "title": "Nodes Settings",
+ "detail": "Details",
+ "log-container": {
+ "title": "Xray logs"
+ }
+ },
+ "dialogs": {
+ "creation": {
+ "title": "Add Node"
+ },
+ "deletion": {
+ "title": "Remove Node"
+ },
+ "edition": {
+ "title": "Edit Node"
+ }
+ },
+ "usage_coefficient": "Usage Coefficient",
+ "add_as_new_host": "Add as new hosts",
+ "certificate-alert": {
+ "title": "Nodes Certificate Configuration",
+ "desc": "If you aim to configure your nodes certificate, checkout settings page.",
+ "click": "Click Here"
+ }
+ },
+ "services": {
+ "settings": {
+ "title": "Service Settings",
+ "detail": "Details"
+ },
+ "dialogs": {
+ "creation": {
+ "title": "Create Service"
+ },
+ "deletion": {
+ "title": "Remove Service"
+ },
+ "edition": {
+ "title": "Edit Service"
+ }
+ }
+ },
+ "users": {
+ "note-placeholder": "Additional information about user",
+ "data_limit": "Data Limit",
+ "used_traffic": "Used Traffic",
+ "data_limit_reset_strategy": "Data Reset Period",
+ "online_at": "Last Use",
+ "expire_date": "Expire Date",
+ "unlimited": "Unlimited",
+ "limited": "Limited",
+ "data_limit_method": "Data limit type",
+ "determined_expire": "Determined",
+ "expire_method": "Expiration",
+ "onhold_expire": "On Hold",
+ "reset_usage": "Reset Usage",
+ "revoke_subscription": "Revoke Subscription",
+ "on_hold_expire_duration": "On Hold",
+ "on_hold_timeout": "On Hold Timeout",
+ "settings": {
+ "subscription_link": {
+ "copied": "Subscription Link Copied",
+ "copy": "Copy Subscription Link",
+ "error": "Unable to copy Subscription Link"
+ }
+ },
+ "services-alert": {
+ "title": "No Service found",
+ "desc": "Make sure you create services to enable your users with inbounds to connect with.",
+ "click": "Click Here"
+ },
+ "dialogs": {
+ "edition": {
+ "title": "Edit User"
+ },
+ "creation": {
+ "title": "Create User"
+ },
+ "deletion": {
+ "title": "Remove User"
+ },
+ "mutation": {
+ "note": {
+ "desc": "Leave a note about your user"
+ }
+ }
+ }
+ },
+ "hosts": {
+ "fragment": {
+ "interval": "Interval",
+ "length": "Length",
+ "packets": "Packets",
+ "length-error": "Length can not exceed 32 char and must be number-number",
+ "interval-error": "Interval can not exceed 32 char and must be number-number",
+ "packets-error": "Packets can not exceed 32 char and must be number-number or be tlshello"
+ },
+ "popover-guide": {
+ "title": "Using this setting, you are able to assign specific address for each inbound.",
+ "desc": "Use these variables to make it dynamic",
+ "username": "Username of the user",
+ "dataUsage": "Current usage of the user",
+ "remainingData": "Remaining data of the user",
+ "dataLimit": "Data limit of the user",
+ "remainingDays": "Remaining days of the user",
+ "expireDate": "Expiry date of the user",
+ "jalaliExpireDate": "Expiry date of the user in jalali calendar",
+ "remainingTime": "Remaining time of the user",
+ "statusEmoji": "User status as an emoji (✅,⌛,🪫,❌,🔌)",
+ "proxyProtocol": "Proxy protocol (e.g. VMess)",
+ "proxyMethod": "Proxy transport method (e.g. ws)",
+ "currentServer": "Marzneshin server ip address",
+ "security": "Security Layer",
+ "host": "Request Host",
+ "port": "Port",
+ "path": "Path",
+ "sni": "SNI",
+ "advancedOptions": "Advanced options",
+ "addHost": "Add host",
+ "savedSuccess": "Host has been saved successfully",
+ "loading": "loading...",
+ "apply": "Apply",
+ "port.info": "By default, the inbound port is advertised to the user. You can set a custom port in case this host forwards traffic from another port to your inbound. For example, the server may forward traffic from port 8443 to the default port of your inbound server.",
+ "path.info": "Set a path for host users, useful behind a reverse proxy.",
+ "sni.info": "By default, a host uses the SNI from the inbound. You can set a custom SNI in case this host is a server that has a different SNI. For example, the server may receive traffic with a different SSL certificate, perform SSL termination, and forward it to your inbound server.",
+ "host.info": "By default, if a request host is set in the Xray config, this host is used. However, you can set a custom request host here if needed.",
+ "security.info": "If the middleware server of this host uses a different security layer than the inbound's default, you can set a custom security layer here.",
+ "alpn": "ALPN",
+ "fingerprint": "Fingerprint",
+ "host.multiHost": "To set multiple addresses, separate them with <badge>,</badge> Each time an address is chosen randomly.",
+ "host.wildcard": "Use <badge>*</badge> to generate a random string (works for wildcard domain names)"
+ },
+ "mux": {
+ "title": "Connection multiplexing",
+ "desc": "Currently supported by v2rayng while using custom config"
+ },
+ "no-inbound-selection-alert": {
+ "title": "No inbound is selected",
+ "desc": "You must select an inbound in order to add a host."
+ },
+ "allowinsecure": "Allow Insecure",
+ "dialogs": {
+ "edition": {
+ "title": "Edit Host"
+ },
+ "creation": {
+ "title": "Add Host"
+ },
+ "deletion": {
+ "title": "Remove Host"
+ },
+ "mutation": {
+ "allowinsecure": {
+ "alert": "Due to security concerns, it's not recommended to enable Allow Insecure"
+ }
+ }
+ }
+ }
+ },
+ "events": {
+ "delete": {
+ "error": "Failed to remove {{name}}",
+ "success": {
+ "title": "{{name}} has been successfully removed",
+ "desc": ""
+ }
+ },
+ "create": {
+ "error": "Failed to create {{name}}",
+ "success": {
+ "title": "{{name}} is successfuly created",
+ "desc": ""
+ }
+ },
+ "update": {
+ "error": "Failed to update {{name}}",
+ "success": {
+ "title": "{{name}} is successfuly updated",
+ "desc": ""
+ }
+ },
+ "user_revoke": {
+ "error": "Failed to revoke {{name}} subscription",
+ "success": {
+ "title": "{{name}} is successfuly created",
+ "desc": ""
+ }
+ },
+ "user_reset": {
+ "error": "Failed to reset {{name}} data usage",
+ "success": {
+ "title": "{{name}} data usage has been successfully reset",
+ "desc": ""
+ }
+ },
+ "user_status": {
+ "error": "Failed to toggle {{name}} enable status",
+ "success": {
+ "title": "{{name}} enable status has been successfully updated",
+ "desc": ""
+ }
+ }
+ },
+ "delete-confirmation": {
+ "title": "Are you sure of this?",
+ "desc": "This action cannot be undone."
+ },
+ "table": {
+ "row-per-page": "Rows per page",
+ "no-result": "No result",
+ "selected": "Selected",
+ "toggle-column": "Toggle columns",
+ "filter-placeholder": "Filter {{name}}"
+ },
+ "statuses": {
+ "active": "Active",
+ "connected": "Connected",
+ "healthy": "Healthy",
+ "disabled": "Disabled",
+ "expired": "Expired",
+ "on_hold": "On Hold",
+ "connecting": "Connecting",
+ "unhealthy": "Unhealthy",
+ "limited": "Limited",
+ "error": "Error"
+ }
}
diff --git a/dashboard/public/locales/fa.json b/dashboard/public/locales/fa.json
index 6c4a8b8..5b8ea7c 100644
--- a/dashboard/public/locales/fa.json
+++ b/dashboard/public/locales/fa.json
@@ -1,162 +1,164 @@
{
- "name": "اسم",
+ "home": "خانه",
+ "name": "نام",
"status": "حالت",
- "address": "ادرس",
- "users": "کاربر ها",
- "nodes": "Nodes",
- "services": "Services",
- "hosts": "Hosts",
+ "address": "آدرس",
+ "users": "کاربران",
+ "nodes": "نود",
+ "services": "سرویسها",
+ "hosts": "هاست",
"username": "یوزرنیم",
- "password": "Password",
- "inbounds": "Inbounds",
- "submit": "Submit",
- "login": "Login",
- "edit": "Edit",
- "actions": "Actions",
- "settings": "Settings",
- "logs": "Logs",
- "note": "Note",
- "config": "Config",
- "tag": "Tag",
- "protocol": "Protocol",
- "online": "Online",
- "offline": "Offline",
- "not_connected": "Not Connected",
- "apply": "Apply",
- "open": "Open",
- "delete": "Delete",
- "port": "Port",
- "create": "Create",
- "path": "Path",
- "host": "Host",
+ "password": "پسوورد",
+ "inbounds": "اینباند ها",
+ "submit": "ارسال",
+ "login": "ورود",
+ "edit": "ویرایش",
+ "actions": "فعالیتها",
+ "settings": "تنظیمات",
+ "logs": "لاگ",
+ "note": "یادداشت",
+ "config": "کانفیگ",
+ "tag": "تگ",
+ "protocol": "پروتکل",
+ "online": "آنلاین",
+ "offline": "آفلاین",
+ "not_connected": "وصل نشده",
+ "apply": "اعمال",
+ "open": "باز کردن",
+ "delete": "حذف",
+ "port": "پورت",
+ "create": "ساخت",
+ "path": "مسیر",
+ "host": "هاست",
"alpn": "ALPN",
- "security": "Security",
- "user_info": "Users Info",
- "subscription": "Subscription",
- "subscription_link": "Subscription Link",
- "fingerprint": "Fingerprint",
+ "security": "امنیت",
+ "user_info": "اطلاعات کاربر",
+ "subscription": "اشتراک",
+ "subscription_link": "لینک اشتراک",
+ "fingerprint": "فینگرپرینت",
"page": {
"settings": {
"certificate": {
- "copy": "Copy Certificate",
- "error": "Certificate Unavailable",
- "copied": "Certificate Copied"
+ "copy": "کپی سرتیفیکت",
+ "error": "سرتیفیکت در دسترس نیست",
+ "copied": "سرتیفیکت کپی شد"
}
},
"login": {
"username": {
"error": {
- "isRequired": "Username is required"
+ "isRequired": "نام کاربری را وارد کنید"
}
},
"password": {
"error": {
- "is-required": "Password is required"
+ "is-required": "رمز عبور را وارد کنید"
}
}
},
"nodes": {
"settings": {
- "title": "Nodes Settings",
- "detail": "Details",
+ "title": "تنظیمات نود",
+ "detail": "جزئیات",
"log-container": {
- "title": "Marznode Xray config logs"
+ "title": "لاگ اکسری"
}
},
"dialogs": {
"creation": {
- "title": "Nodes Creation"
+ "title": "افزودن نود"
},
"deletion": {
- "title": "Nodes Deletion"
+ "title": "حذف نود"
},
"edition": {
- "title": "Nodes Edition"
+ "title": "ویرایش نود"
}
},
- "usage_coefficient": "Usage Coefficient",
- "add_as_new_host": "Add as new hosts",
+ "usage_coefficient": "ضریب مصرف",
+ "add_as_new_host": "افزودن هاست های وابسته",
"certificate-alert": {
- "title": "Nodes Certificate Configuration",
- "desc": "If you aim to configure your nodes certificate, checkout settings page.",
- "click": "Click Here"
+ "title": "کانفیگ سرتیفیکت نود",
+ "desc": "اگر قصد برداشت سرتیفیکت نود را دارید، صفحه تنظیمات را بررسی کنید",
+ "click": "اینجا کلیک کنید"
}
},
"services": {
"settings": {
- "title": "Servicecs Settings",
- "detail": "Details"
+ "title": "تنظیمات سرویس",
+ "detail": "جزئیات"
},
"dialogs": {
"creation": {
- "title": "Services Creation"
+ "title": "ساخت سرویس"
},
"deletion": {
- "title": "Services Deletion"
+ "title": "حذف سرویس"
},
"edition": {
- "title": "Services Edition"
+ "title": "ویرایش سرویس"
}
}
},
"users": {
- "data_limit": "Data Limit",
- "used_traffic": "Used Traffic",
- "data_limit_reset_strategy": "Data Limit Reset Strategy",
- "online_at": "Online At",
- "expire_date": "Expire Date",
- "unlimited": "Unlimited",
- "determined_expire": "Determined",
- "expire_method": "Expiration method",
- "onhold_expire": "On Hold",
- "reset_usage": "Reset Usage",
- "revoke_subscription": "Revoke Subscription",
- "on_hold_expire_duration": "On Hold",
- "on_hold_timeout": "On Hold Timeout",
+ "note-placeholder": "یادداشتی در مورد کاربر",
+ "data_limit": "محدودیت حجم",
+ "used_traffic": "ترافیک مصرفی",
+ "data_limit_reset_strategy": "بازه ریست حجم مصرفی",
+ "online_at": "آخرین استفاده",
+ "expire_date": "تاریخ انقضا",
+ "unlimited": "نامحدود",
+ "determined_expire": "مشخص",
+ "expire_method": "انقضا",
+ "onhold_expire": "شروع از اولین اتصال",
+ "reset_usage": "ریست حجم مصرفی",
+ "revoke_subscription": "ابطال اشتراک",
+ "on_hold_expire_duration": "مدت زمان",
+ "on_hold_timeout": "انقضا",
"settings": {
"subscription_link": {
- "copied": "Subscription Link Copied",
- "copy": "Copy Subscription Link",
- "error": "Unable to copy Subscription Link"
+ "copied": "لینک اشتراک کپی شد",
+ "copy": "کپی لینک اشتراک",
+ "error": "لینک اشتراک کپی نشد"
}
},
"services-alert": {
- "title": "No Service were found",
- "desc": "Make sure you create services to enable your users with inbounds to connect with.",
- "click": "Click Here"
+ "title": "سرویسی یافت نشد",
+ "desc": "برای ساخت یوزر ابتدا سرویسی ایجاد کنید",
+ "click": "اینجا را کلیک کنید"
},
"dialogs": {
"edition": {
- "title": "Users Edition"
+ "title": "ویرایش کاربر"
},
"creation": {
- "title": "Users Creation"
+ "title": "افزودن کاربر"
},
"deletion": {
- "title": "Users Deletion"
+ "title": "حذف کاربر"
},
"mutation": {
"note": {
- "desc": "Leave a note about your user"
+ "desc": "یادداشت"
}
}
}
},
"hosts": {
- "allowinsecure": "Allow insecure",
+ "allowinsecure": "پذیرش کانکشن ناامن",
"dialogs": {
"edition": {
- "title": "Hosts Edition"
+ "title": "ویرایش هاست"
},
"creation": {
- "title": "Hosts Creation"
+ "title": "افزودن هاست"
},
"deletion": {
- "title": "Hosts Deletion"
+ "title": "حذف هاست"
},
"mutation": {
"allowinsecure": {
- "alert": "Due to security concerns, it is not recommended to allow Insecure"
+ "alert": "فعال کردن این گزینه پیشنهاد نمÛشود."
}
}
}
@@ -164,30 +166,30 @@
},
"events": {
"delete": {
- "error": "Failed to delete {{name}}",
+ "error": "خطا در حذف {{name}}",
"success": {
- "title": "{{name}} is successfuly deleted",
+ "title": "با موفقیت حذف شد {{name}}",
"desc": ""
}
},
"create": {
- "error": "Failed to create {{name}}",
+ "error": "خطا در حذف {{name}}",
"success": {
- "title": "{{name}} is successfuly created",
+ "title": "{{name}} با موفقیت حذف شد",
"desc": ""
}
},
"update": {
- "error": "Failed to update {{name}}",
+ "error": "خطا در آپدیت {{name}}",
"success": {
- "title": "{{name}} is successfuly updated",
+ "title": "{{name}} با موفقیت آپدیت شد",
"desc": ""
}
},
"user_revoke": {
- "error": "Failed to revoke {{name}} subscription",
+ "error": "خطا در ابطال اشتراک {{name}}",
"success": {
- "title": "{{name}} is successfuly created",
+ "title": "با موفقیت ایجاد شد.{{name}}",
"desc": ""
}
},
@@ -200,8 +202,8 @@
}
},
"delete-confirmation": {
- "title": "Are you sure of this?",
- "desc": "This action cannot be undone. This will permanently delete your account and remove your data from our servers."
+ "title": "آیا از انجام این کار مطمئنید؟",
+ "desc": "حذف اطلاعات بازگشت ناپذیر است."
},
"table": {
"row-per-page": "Rows per page",
@@ -211,15 +213,15 @@
"filter-placeholder": "Filter {{name}}"
},
"statuses": {
- "active": "Active",
- "connected": "Connected",
- "healthy": "Healthy",
- "disabled": "Disabled",
- "expired": "Expired",
- "on_hold": "On Hold",
- "connecting": "Connecting",
- "unhealthy": "Unhealthy",
- "limited": "Limited",
- "error": "Error"
+ "active": "فعال",
+ "connected": "متصل شده",
+ "healthy": "سالم",
+ "disabled": "غیرفعال",
+ "expired": "منقضی",
+ "on_hold": "شروع از اولین اتصال",
+ "connecting": "در حال اتصال",
+ "unhealthy": "ناسالم",
+ "limited": "محدود شده",
+ "error": "خطا"
}
}
diff --git a/dashboard/public/locales/kur.json b/dashboard/public/locales/kur.json
index 37dd92b..2486032 100644
--- a/dashboard/public/locales/kur.json
+++ b/dashboard/public/locales/kur.json
@@ -35,33 +35,36 @@
"save": "Seyv Bike",
"days": "Roj",
"home": "Malê",
+ "light": "Runak",
+ "dark": "Tarîk",
+ "system": "Sîstim",
"advanced-options": "Bijardikanî pêşkewtû",
"page": {
"settings": {
"certificate": {
- "copy": "Copy Certificate",
- "error": "Certificate Unavailable",
- "copied": "Certificate Copied"
+ "copy": "Kopî Birrwaname",
+ "error": "Birrwaname berdest nîye",
+ "copied": "Birrwaname Kopî kira"
}
},
"login": {
"username": {
"error": {
- "isRequired": "Username is required"
+ "isRequired": "Nawî bekarhêner pêwîste"
}
},
"password": {
"error": {
- "is-required": "Password is required"
+ "is-required": "Têperwişe pêwîste"
}
}
},
"nodes": {
"settings": {
- "title": "Nodes Settings",
- "detail": "Details",
+ "title": "Sazkarîyekanî Node",
+ "detail": "Wurdekaryekan",
"log-container": {
- "title": "Marznode Xray config logs"
+ "title": "Xray logs"
}
},
"dialogs": {
@@ -101,6 +104,7 @@
}
},
"users": {
+ "note-placeholder": "Têbînî leser bekarhêner",
"data_limit": "Sinûrî data",
"used_traffic": "Traffic bekarhêndiraw",
"data_limit_reset_strategy": "Şêwazî sirrinewey sinûrî data",
diff --git a/dashboard/src/components/header/index.tsx b/dashboard/src/components/header/index.tsx
index 8fb3e0a..9e75aa0 100644
--- a/dashboard/src/components/header/index.tsx
+++ b/dashboard/src/components/header/index.tsx
@@ -1,8 +1,8 @@
-import { LanguageSwitch } from "@marzneshin/features/language-switch"
-import { ThemeToggle } from "@marzneshin/features/theme-switch"
-import { Logout } from "@marzneshin/features/auth"
-import { Link } from "@tanstack/react-router"
-import { FC, PropsWithChildren } from "react"
+import { LanguageSwitch } from "@marzneshin/features/language-switch";
+import { ThemeToggle } from "@marzneshin/features/theme-switch";
+import { Logout } from "@marzneshin/features/auth";
+import { Link } from "@tanstack/react-router";
+import { FC, PropsWithChildren } from "react";
export const Header: FC<PropsWithChildren> = ({ children }) => {
return (
@@ -21,5 +21,5 @@ export const Header: FC<PropsWithChildren> = ({ children }) => {
<ThemeToggle />
</div>
</div>
- )
-}
+ );
+};
diff --git a/dashboard/src/features/auth/logout/index.tsx b/dashboard/src/features/auth/logout/index.tsx
index e2e55d4..16be1a5 100644
--- a/dashboard/src/features/auth/logout/index.tsx
+++ b/dashboard/src/features/auth/logout/index.tsx
@@ -1,22 +1,23 @@
-
-import { Button } from '@marzneshin/components';
-import { useNavigate } from '@tanstack/react-router';
-import { LogOut } from 'lucide-react';
-import { FC, useCallback } from 'react'
+import { Button } from "@marzneshin/components";
+import { useNavigate } from "@tanstack/react-router";
+import { LogOut } from "lucide-react";
+import { FC, useCallback } from "react";
interface LogoutProps { }
export const Logout: FC<LogoutProps> = () => {
- const navigate = useNavigate({ from: '/' })
- const handleLogout = useCallback(
- () => {
- navigate({ to: '/login' })
- },
- [navigate],
- )
+ const navigate = useNavigate({ from: "/" });
+ const handleLogout = useCallback(() => {
+ navigate({ to: "/login" });
+ }, [navigate]);
return (
- <Button className="h-full" size="icon" onClick={handleLogout}>
+ <Button
+ className="h-full text-secondary bg-gray-800 dark:hover:bg-secondary-foreground dark:hover:text-secondary dark:text-secondary-foreground"
+ size="icon"
+ variant="outline"
+ onClick={handleLogout}
+ >
<LogOut className="h-[1rem] w-[1rem]" />
</Button>
);
-}
+};
diff --git a/dashboard/src/features/language-switch/index.tsx b/dashboard/src/features/language-switch/index.tsx
index 8da9110..5862352 100644
--- a/dashboard/src/features/language-switch/index.tsx
+++ b/dashboard/src/features/language-switch/index.tsx
@@ -1,43 +1,53 @@
-import { Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@marzneshin/components";
+import {
+ Button,
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@marzneshin/components";
import { Languages } from "lucide-react";
import { FC } from "react";
import { useTranslation } from "react-i18next";
export const LanguageSwitch: FC = () => {
- const { i18n } = useTranslation();
+ const { i18n } = useTranslation();
- const changeLanguage = (lang: string) => {
- i18n.changeLanguage(lang);
- };
+ const changeLanguage = (lang: string) => {
+ i18n.changeLanguage(lang);
+ };
- return (
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <Button variant="outline" className="bg-secondary-foreground text-primary-foreground " size="icon">
- <Languages className="h-[1rem] w-[1rem]" />
- <span className="sr-only">Toggle Language</span>
- </Button>
- </DropdownMenuTrigger>
- <DropdownMenuContent align="end">
- <DropdownMenuItem onClick={() => changeLanguage("en")}>
- English
- </DropdownMenuItem>
- <DropdownMenuItem onClick={() => changeLanguage("kmr")}>
- Kurdî Kurmancî
- </DropdownMenuItem>
- <DropdownMenuItem onClick={() => changeLanguage("kur")}>
- Kurdî Nawendî (Latin)
- </DropdownMenuItem>
- <DropdownMenuItem onClick={() => changeLanguage("ckb")}>
- کوردی ناوەندی
- </DropdownMenuItem>
- <DropdownMenuItem onClick={() => changeLanguage("fa")}>
- فارسی
- </DropdownMenuItem>
- <DropdownMenuItem onClick={() => changeLanguage("fa")}>
- Русский
- </DropdownMenuItem>
- </DropdownMenuContent>
- </DropdownMenu>
- );
+ return (
+ <DropdownMenu>
+ <DropdownMenuTrigger asChild>
+ <Button
+ variant="outline"
+ className="bg-gray-800 text-secondary dark:hover:bg-secondary-foreground dark:hover:text-secondary dark:text-secondary-foreground"
+ size="icon"
+ >
+ <Languages className="h-[1rem] w-[1rem]" />
+ <span className="sr-only">Toggle Language</span>
+ </Button>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent align="end">
+ <DropdownMenuItem onClick={() => changeLanguage("en")}>
+ English
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => changeLanguage("kmr")}>
+ Kurdî Kurmancî
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => changeLanguage("kur")}>
+ Kurdî Soranî
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => changeLanguage("ckb")}>
+ کوردی سورانی
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => changeLanguage("fa")}>
+ فارسی
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => changeLanguage("ru")}>
+ Русский
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
+ );
};
diff --git a/dashboard/src/features/theme-switch/theme-toggle/index.tsx b/dashboard/src/features/theme-switch/theme-toggle/index.tsx
index 60ed833..00b4133 100644
--- a/dashboard/src/features/theme-switch/theme-toggle/index.tsx
+++ b/dashboard/src/features/theme-switch/theme-toggle/index.tsx
@@ -1,4 +1,4 @@
-import { Moon, Sun } from "lucide-react"
+import { Moon, Sun } from "lucide-react";
import {
Button,
@@ -6,17 +6,21 @@ import {
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
-} from "@marzneshin/components"
-import { useTheme } from "../theme-provider"
-import { useTranslation } from "react-i18next"
+} from "@marzneshin/components";
+import { useTheme } from "../theme-provider";
+import { useTranslation } from "react-i18next";
export function ThemeToggle() {
- const { setTheme } = useTheme()
- const { t } = useTranslation()
+ const { setTheme } = useTheme();
+ const { t } = useTranslation();
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
- <Button variant="outline" className="bg-secondary-foreground text-primary-foreground" size="icon">
+ <Button
+ variant="outline"
+ className="bg-gray-800 text-secondary dark:hover:bg-secondary-foreground dark:hover:text-secondary dark:text-secondary-foreground"
+ size="icon"
+ >
<Sun className="transition-all scale-100 rotate-0 dark:scale-0 dark:-rotate-90 h-[1rem] w-[1rem]" />
<Moon className="absolute transition-all scale-0 rotate-90 dark:scale-100 dark:rotate-0 h-[1rem] w-[1rem]" />
<span className="sr-only">Toggle theme</span>
@@ -24,15 +28,15 @@ export function ThemeToggle() {
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>
- {t('light')}
+ {t("light")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>
- {t('dark')}
+ {t("dark")}
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>
- {t('system')}
+ {t("system")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
- )
+ );
}
diff --git a/dashboard/src/features/users/dialogs/mutation/fields/note.tsx b/dashboard/src/features/users/dialogs/mutation/fields/note.tsx
index d84a79b..f0af1c8 100644
--- a/dashboard/src/features/users/dialogs/mutation/fields/note.tsx
+++ b/dashboard/src/features/users/dialogs/mutation/fields/note.tsx
@@ -4,28 +4,27 @@ import {
FormItem,
Textarea,
FormLabel,
- FormMessage
-} from '@marzneshin/components';
-import { FC } from 'react'
-import { useFormContext } from 'react-hook-form';
-import { useTranslation } from 'react-i18next';
-
+ FormMessage,
+} from "@marzneshin/components";
+import { FC } from "react";
+import { useFormContext } from "react-hook-form";
+import { useTranslation } from "react-i18next";
interface NoteFieldProps { }
export const NoteField: FC<NoteFieldProps> = () => {
- const { t } = useTranslation()
- const form = useFormContext()
+ const { t } = useTranslation();
+ const form = useFormContext();
return (
<FormField
control={form.control}
name="note"
render={({ field }) => (
<FormItem>
- <FormLabel>{t('note')}</FormLabel>
+ <FormLabel>{t("note")}</FormLabel>
<FormControl>
<Textarea
- placeholder="Additional information about data"
+ placeholder={t("page.users.note-placeholder")}
className="resize-none"
{...field}
/>
@@ -35,4 +34,4 @@ export const NoteField: FC<NoteFieldProps> = () => {
)}
/>
);
-}
+};