diff --git a/app/chat/page.tsx b/app/chat/page.tsx
index 0b609e8..40c1043 100644
--- a/app/chat/page.tsx
+++ b/app/chat/page.tsx
@@ -1,18 +1,98 @@
-"use client"
-import { useState, useEffect, useRef } from 'react';
-import { useTheme } from 'next-themes';
-import { Textarea } from '@/components/ui/textarea';
-import { ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable';
-import { Badge } from '@/components/ui/badge';
-import { Forward, Reply, ChevronUp, ChevronDown } from 'lucide-react';
-import { toast } from 'sonner';
+"use client";
+import { useState, useEffect, useRef } from "react";
+import { useTheme } from "next-themes";
+import { Textarea } from "@/components/ui/textarea";
+import { ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable";
+import { Badge } from "@/components/ui/badge";
+import { Forward, Reply, ChevronUp, ChevronDown } from "lucide-react";
+import { toast } from "sonner";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
-} from '@/components/ui/tooltip';
-import { Button } from '@/components/ui/button';
+} from "@/components/ui/tooltip";
+import { Button } from "@/components/ui/button";
+
+const url = "https://example.com"; // Replace with your actual URL
+const API_ENDPOINT = `${url}/messages`;
+const CONVERSATION_API_ENDPOINT = `${url}/conversations`;
+const DISCORD_API_ENDPOINT = `${url}/create-discord-channel`;
+const DISCORD_MESSAGE_API_ENDPOINT = `${url}/send-discord-message`;
+const SYNC_ENDPOINT = `${url}/sync`;
+
+const createConversationInAPI = async (conversation: { name: string; id: number; members: string[]; tags: string[] }) => {
+ try {
+ const response = await fetch(`${CONVERSATION_API_ENDPOINT}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(conversation),
+ });
+
+ if (!response.ok) {
+ throw new Error(`API error: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ return data;
+ } catch (error) {
+ console.error('Error creating conversation in API:', error);
+ toast.error('Failed to create conversation on the server.');
+ }
+};
+
+const syncMessages = async (conversationId: number) => {
+ try {
+ const response = await fetch(`${SYNC_ENDPOINT}?conversationId=${conversationId}`);
+ if (!response.ok) {
+ throw new Error(`API error: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ if (!data || (Array.isArray(data) && data.length === 0)) {
+ console.log("No messages found. Conversation may be new.");
+ return [];
+ }
+
+ return data;
+ } catch (error) {
+ console.error("Error syncing messages:", error);
+ toast.error("Failed to sync messages from the server.");
+ }
+};
+
+
+type CreateChannelOptions = {
+ name: string;
+ topic?: string;
+ isPrivate?: boolean;
+ categoryId?: string;
+};
+
+const createDiscordChannel = async (options: CreateChannelOptions) => {
+ try {
+ const response = await fetch(DISCORD_API_ENDPOINT, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(options),
+ });
+
+ if (!response.ok) {
+ throw new Error(`Discord API error: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ return data;
+ } catch (error) {
+ console.error('Error creating Discord channel:', error);
+ toast.error('Failed to create Discord channel.');
+ }
+};
+
const convertMarkdownToHTML = (text: string) => {
return text
@@ -164,8 +244,15 @@ const ChatMessage = ({message, message_index, messages, reply_func, searchText,
} text-sm ${isSameSideNext ? 'pb-2' : 'pb-4'} group`;
const messageContentClass = `p-3 rounded-lg relative group ${
- isRight ? isSameSideNext ? '' : 'rounded-br-none' : isSameSideNext ? '' : 'rounded-bl-none'
- } bg-gray-200 text-black dark:bg-[#303030] dark:text-foreground`;
+ isRight
+ ? isSameSideNext
+ ? ""
+ : "rounded-br-none"
+ : isSameSideNext
+ ? ""
+ : "rounded-bl-none"
+ } bg-black text-white`;
+
return (
@@ -252,6 +339,20 @@ export default function Home() {
const matchElements = useRef<(HTMLElement | null)[]>([]);
const [isSearching, setIsSearching] = useState(false);
+ useEffect(() => {
+ const syncData = async () => {
+ if (!conversationData?.id) return; // Avoid running sync if no conversationData
+
+ const messages = await syncMessages(conversationData.id);
+ const updatedConversations = [...conversations];
+ updatedConversations[conversationIndex].messages = messages;
+ setConversations(updatedConversations);
+ };
+
+ const interval = setInterval(syncData, 1500);
+ return () => clearInterval(interval);
+ }, [conversationIndex, conversations]);
+
useEffect(() => {
if (!isSearching) {
scrollToBottom();
@@ -267,19 +368,21 @@ export default function Home() {
const matches: { messageIndex: number; globalMatchIndex: number }[] = [];
const newMessageMatchStarts: Record
= {};
- conversationData.messages.forEach((message, messageIndex) => {
- newMessageMatchStarts[messageIndex] = globalMatchIndex;
-
- if (message instanceof Message && searchText) {
- const matchArray =
- message.text.match(new RegExp(escapeRegExp(searchText), 'gi')) || [];
-
- matchArray.forEach(() => {
- matches.push({ messageIndex, globalMatchIndex });
- globalMatchIndex++;
- });
- }
- });
+ if (conversationData?.messages) {
+ conversationData.messages.forEach((message, messageIndex) => {
+ newMessageMatchStarts[messageIndex] = globalMatchIndex;
+
+ if (message instanceof Message && searchText) {
+ const matchArray =
+ message.text.match(new RegExp(escapeRegExp(searchText), "gi")) || [];
+
+ matchArray.forEach(() => {
+ globalMatchIndex++;
+ });
+ }
+ });
+ }
+
setMessageMatchStarts(newMessageMatchStarts);
setTotalMatches(globalMatchIndex);
@@ -349,44 +452,55 @@ export default function Home() {
if (scrollAreaRef.current) {
scrollAreaRef.current.scrollTo({
top: scrollAreaRef.current.scrollHeight,
- behavior: 'smooth',
+ behavior: "smooth",
});
}
};
- const sendMessage = (text: string) => {
+
+
+ const sendMessage = async (text: string) => {
const cleanedText = text.trim();
- if (cleanedText === '') {
- toast.error('Message cannot be empty!');
+ if (cleanedText === "") {
+ toast.error("Message cannot be empty!");
return;
}
-
- const updatedMessages = [
- ...conversations[conversationIndex].messages,
- new Message(conversations[conversationIndex].messages.length + 1, 'You', cleanedText, 'right', replyingTo ? replyingTo.text : undefined),
- ];
-
- const updatedConversation = {
- ...conversations[conversationIndex],
- messages: updatedMessages,
- };
-
- const updatedConversations = [...conversations];
- updatedConversations[conversationIndex] = updatedConversation;
-
- setConversations(updatedConversations);
- setReplyingTo(null);
- setTextboxText('');
-
- setTimeout(() => {
- scrollToBottom();
- }, 100);
- };
-
- const reply = (message_text: string, username: string) => {
- setReplyingTo({ text: message_text, username });
- inputRef.current?.focus();
+
+ const currentConversation = conversations[conversationIndex];
+
+ if (!currentConversation) {
+ toast.error("No conversation selected.");
+ return;
+ }
+
+ try {
+ await sendMessageToAPI(currentConversation.id, cleanedText);
+
+ const messageData = {
+ id: (currentConversation.messages?.length || 0) + 1,
+ text: cleanedText,
+ username: "You",
+ timestamp: new Date().toISOString(),
+ };
+
+ const updatedMessages = [
+ ...(currentConversation.messages || []),
+ messageData,
+ ];
+
+ const updatedConversations = [...conversations];
+ updatedConversations[conversationIndex] = {
+ ...currentConversation,
+ messages: updatedMessages,
+ };
+
+ setConversations(updatedConversations);
+ setTextboxText("");
+ } catch (error) {
+ console.error("Error sending message:", error);
+ }
};
+
const toggleSearchBox = () => {
if (showSearchBox) {
@@ -396,16 +510,91 @@ export default function Home() {
}
setShowSearchBox(!showSearchBox);
};
-
- const handleNewConversation = () => {
- const newConversation = new Conversation('New Conversation', conversations.length + 1, ['You', 'Developer'], [],['Tag']);
+ const sendMessageToAPI = async (conversationId: number, message: string) => {
+ try {
+ const response = await fetch(`${API_ENDPOINT}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ conversationId,
+ message,
+ }),
+ });
+
+ if (!response.ok) {
+ throw new Error(`API error: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+
+ // Send the message to Discord as well
+ await sendDiscordMessage(conversationId, message);
+
+ return data;
+ } catch (error) {
+ console.error('Error sending message to API:', error);
+ toast.error('Failed to send message to the server.');
+ }
+ };
+ const sendDiscordMessage = async (conversationId: number, message: string) => {
+ try {
+ const response = await fetch(DISCORD_MESSAGE_API_ENDPOINT, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ conversationId,
+ message,
+ }),
+ });
+
+ if (!response.ok) {
+ throw new Error(`Discord API error: ${response.statusText}`);
+ }
+
+ const data = await response.json();
+ return data;
+ } catch (error) {
+ console.error('Error sending message to Discord:', error);
+ toast.error('Failed to send message to Discord.');
+ }
+ };
+
+ const handleNewConversation = async () => {
+ const newConversation = new Conversation(
+ 'New Conversation',
+ conversations.length + 1,
+ ['You', 'Developer'],
+ [],
+ ['Tag']
+ );
+
+ await createConversationInAPI({
+ name: newConversation.name,
+ id: newConversation.id,
+ members: newConversation.members,
+ tags: newConversation.tags,
+ });
+
+ const discordChannel = await createDiscordChannel({
+ name: newConversation.name,
+ });
+
+ if (discordChannel && discordChannel.channelId) {
+ newConversation.id = discordChannel.channelId;
+ }
+
setConversations([...conversations, newConversation]);
setConversationIndex(conversations.length);
-
+
setTimeout(() => {
scrollToBottom();
}, 50);
};
+
useEffect(() => {
const handleGlobalKeyDown = (event: any) => {
@@ -428,7 +617,7 @@ export default function Home() {
}, [showSearchBox]);
return (
-
+
{showSearchBox && (
)}
@@ -463,25 +652,21 @@ export default function Home() {
-
-
-
-
-
- {conversationData.messages.map((message, index) => {
- if (message instanceof Message) {
- return (
-
- );
- } else if (message instanceof ConversationEvent) {
- return ;
- }
- return null;
- })}
-
-
+
+
+
+ {conversationData?.messages?.length > 0 ? (
+ conversationData.messages.map((message, index) => (
+
+
+ {message.username}: {message.text}
+
+
+ ))
+ ) : (
+
No messages to display
+ )}
-
{replyingTo && (
@@ -501,4 +686,4 @@ export default function Home() {
);
-}
+}
\ No newline at end of file
diff --git a/translations/ps.yaml b/translations/ps.yaml
new file mode 100644
index 0000000..18305e7
--- /dev/null
+++ b/translations/ps.yaml
@@ -0,0 +1,104 @@
+Language:
+ name: "پښتو"
+ name_en: "Pashto"
+ iso_code: "ps"
+ credits: "ضیا"
+ version: "2.0.0"
+
+Translations:
+
+ # MARK: Globals
+
+ confirm: "تایید"
+ cancel: "لغوه"
+ 'yes': "هو"
+ 'no': "نه"
+ continue: "دوام ورکړئ"
+ loading: "لوډېږي..."
+ success: "بریا"
+ error: "تېروتنه"
+ done: "بشپړ شو!"
+ set: "تنظیم شوی"
+ setting: "تنظیمېږي..."
+ unknown: "نامعلوم"
+ download: "ډاونلوډ"
+ downloading: "ډاونلوډېږي {0}..."
+ clear: "پاک کړئ"
+ search: "لټون وکړئ"
+ submit: "سپارل"
+ install: "انسټال کړئ"
+ uninstall: "ان انسټال کړئ"
+
+ # MARK: Backend
+
+ main.errors_and_warnings: "په لاګ فایلونو کې تېروتنې او خبرداري:"
+ main.errors: "تېروتنې:"
+ main.warnings: "خبرداري:"
+ main.no_errors_or_warnings: "هیڅ تېروتنه یا خبرداری ونه موندل شو."
+ main.overseer_started: "ETS2LA Overseer پیل شو!"
+ main.development_mode: "ETS2LA د پرمختیايي حالت کې روان دی."
+ main.restarting: "ETS2LA بیا پیلېږي..."
+ main.updating: "ETS2LA تازه کېږي..."
+ main.update_done: "تازه کول پای ته ورسید... بیا پیلېږي!"
+ main.crashed: "ETS2LA د لاندې تېروتنې سره کریش شو:"
+ main.legacy_traceback: "د تېروتنې تریس بیک پخوانی حالت وکارول شو."
+ main.send_report: "پورته تریس بیک پراختیا کونکو ته واستوئ."
+ main.closed: "ETS2LA بند شو."
+ main.press_enter: "د وتلو لپاره انټر ووهئ..."
+ core.backend_started: "ETS2LA بیک اینډ بریالۍ پیل شو."
+ immediate.websocket_started: "ویب ساکټ پیل شو."
+ immediate.message_error: "د پیغام پروسس کولو پر مهال تېروتنه رامنځته شوه."
+ immediate.empty_page: "خالي پاڼه لیږل شوې وه."
+ webserver.enabling_plugin: "پلګین فعالېږي {0}"
+ webserver.disabling_plugin: "پلګین غیر فعالېږي {0}"
+ webserver.webserver_started: "ویب سرور په {0} ( {1} ) پیل شو"
+ webserver.frontend_started: "فرنټ اینډ په {0} ( {1} ) پیل شو"
+ godot.server_started: "ګودوت سرور د {0} پورټ باندې کار کوي"
+ webpage.opened: "ETS2LA UI خلاص شو."
+ webpage.ui_loading: "مهرباني وکړئ انتظار وکړئ، د کارونکي انٹرفېس چمتو کېږي"
+ controls.listener_started: "د کنټرولونو اوریدونکی فعال شو."
+ sounds.missing_sound: "ساؤنډپېک '{0}' کې اړین غږ '{1}' نشته."
+ sounds.invalid_file_type: "ساؤنډپېک '{0}' د غلط فایل ډول '{1}' لري."
+ sounds.sound_not_found_in_soundpack: "د '{0}' غږ غږول غوښتل، خو دا په '{1}' ساؤنډپېک کې نه و موندل شوی."
+ logging.delete_log_error: "د لاګ فایل حذف نشو."
+ logging.logger_initialized: "لاګر پیل شو."
+ events.vehicle_change.vehicle_change: "د موټر بدلون کشف شو."
+ events.vehicle_change.vehicle_change_description: "موږ نوی موټر کشف کړی. مهرباني وکړئ F4 فشار ورکړئ، د سیټ تنظیمات خلاص کړئ، او خپل نوی FOV ارزښت داخل کړئ."
+
+ # MARK: Tutorials
+
+ tutorials.main.window_controls: "دا د کړکۍ کنټرولونه دي. چپ اړخ بټن اضافي اختیارونه لري، دا وڅیړئ!"
+ tutorials.main.slide_area: "تاسو کولی شئ کړکۍ حرکت ورکړئ د دې ساحې کلیکولو او کشولو سره."
+ tutorials.main.sidebar_collapse: "تاسو کولی شئ سایډ بار پټ کړئ او 'بشپړ پرده' حالت ته لاړ شئ."
+ tutorials.main.sidebar: "تاسو کولی شئ د سایډبار له لارې د ایپ مختلف پاڼې خلاص کړئ."
+ tutorials.main.settings: "د ترتیب پاڼې ته لاړ شئ!"
+ tutorials.settings.static: "دلته هغه تنظیمات دي چې د ټول ایپ لپاره اړین دي."
+ tutorials.settings.global: "تاسو اوس مهال د ایپ عمومي تنظیمات ګورئ."
+ tutorials.settings.plugin: "دا د ټولو پلګینونو لیست دی چې د ترتیب پاڼې لري."
+ tutorials.settings.sdk: "د وروستي مرحلې لپاره، د SDK ترتیباتو پاڼه خلاصه کړئ او دا نصب کړئ."
+
+ # MARK: Plugins
+
+ plugins.adaptivecruisecontrol: "موافقه شوې کروز کنټرول"
+ plugins.adaptivecruisecontrol.description: "دا د مخکې موټر لپاره سرعت کموي (که د څیزونو کشف فعال وي)."
+ plugins.map: "نقشه"
+ plugins.map.description: "د نقشې کشف پلګین."
+ plugins.objectdetection: "د څیزونو کشف"
+ plugins.objectdetection.description: "کمپیوټر ویژن د څیزونو کشف لپاره کاروي."
+ plugins.trafficlightdetection: "د ترافیک څراغ کشف"
+ plugins.trafficlightdetection.description: "دا د ترافیک څراغونه کشفوي او د کروز کنټرول سیسټم سره یوځای کوي."
+
+ # MARK: About
+
+ about.about: "زموږ په اړه"
+ about.description: "ETS2LA یوه پروژه ده چې د ETS2 او ATS لپاره د اتومات چلولو آسانه حلونه برابروي."
+ about.statistics: "احصایې"
+ about.statistics.users_online: "آنلاین کارونکي:"
+ about.statistics.users_online_value: "{0} کارونکي"
+ about.statistics.past_24h: "وروستۍ 24 ساعته:"
+ about.statistics.past_24h_value: "{0} ځانګړي کارونکي"
+ about.developers: "پرمختیا کونکي / شراکت داران"
+ about.translation_credits: "د ژباړې کریډیټونه"
+ about.no_credits: "د دې ژبې لپاره هیڅ کریډیټ نشته."
+ about.support_development: "د پرمختګ ملاتړ وکړئ"
+ about.kofi_description: "• که تاسو پروژه خوښوئ، تاسو کولی شئ د Ko-Fi له لارې مرسته وکړئ."
diff --git a/translations/ur.yaml b/translations/ur.yaml
new file mode 100644
index 0000000..40f32d3
--- /dev/null
+++ b/translations/ur.yaml
@@ -0,0 +1,104 @@
+Language:
+ name: "اردو"
+ name_en: "Urdu"
+ iso_code: "ur"
+ credits: "ضياء"
+ version: "2.0.0"
+
+Translations:
+
+ # MARK: Globals
+
+ confirm: "تصدیق کریں"
+ cancel: "منسوخ کریں"
+ 'yes': "ہاں"
+ 'no': "نہیں"
+ continue: "جاری رکھیں"
+ loading: "لوڈ ہو رہا ہے..."
+ success: "کامیابی"
+ error: "غلطی"
+ done: "مکمل!"
+ set: "سیٹ"
+ setting: "سیٹ کیا جا رہا ہے..."
+ unknown: "نامعلوم"
+ download: "ڈاؤن لوڈ"
+ downloading: "ڈاؤن لوڈ ہو رہا ہے {0}..."
+ clear: "صاف کریں"
+ search: "تلاش کریں"
+ submit: "جمع کریں"
+ install: "انسٹال کریں"
+ uninstall: "اَن انسٹال کریں"
+
+ # MARK: Backend
+
+ main.errors_and_warnings: "لاگ فائل میں غلطیاں اور وارننگز:"
+ main.errors: "غلطیاں:"
+ main.warnings: "وارننگز:"
+ main.no_errors_or_warnings: "کوئی غلطی یا وارننگ نہیں ملی۔"
+ main.overseer_started: "ETS2LA Overseer شروع ہو گیا!"
+ main.development_mode: "ETS2LA ڈویلپمنٹ موڈ میں چل رہا ہے۔"
+ main.restarting: "ETS2LA دوبارہ شروع ہو رہا ہے..."
+ main.updating: "ETS2LA اپ ڈیٹ ہو رہا ہے..."
+ main.update_done: "اپ ڈیٹ مکمل... دوبارہ شروع ہو رہا ہے!"
+ main.crashed: "ETS2LA مندرجہ ذیل غلطی کے ساتھ کریش ہو گیا:"
+ main.legacy_traceback: "پرانا ٹریس بیک استعمال کیا گیا۔"
+ main.send_report: "اوپر دیا گیا ٹریس بیک ڈیولپرز کو بھیجیں۔"
+ main.closed: "ETS2LA بند ہو گیا۔"
+ main.press_enter: "باہر نکلنے کے لیے انٹر دبائیں..."
+ core.backend_started: "ETS2LA بیک اینڈ کامیابی سے شروع ہو گیا۔"
+ immediate.websocket_started: "ویب ساکٹ شروع ہو گیا۔"
+ immediate.message_error: "پیغام پراسیس کرنے میں غلطی ہوئی۔"
+ immediate.empty_page: "خالی صفحہ بھیجنے کی کوشش کی گئی۔"
+ webserver.enabling_plugin: "پلگ ان فعال کیا جا رہا ہے {0}"
+ webserver.disabling_plugin: "پلگ ان غیر فعال کیا جا رہا ہے {0}"
+ webserver.webserver_started: "ویب سرور {0} ( {1} ) پر شروع ہو گیا"
+ webserver.frontend_started: "فرنٹ اینڈ {0} ( {1} ) پر شروع ہو گیا"
+ godot.server_started: "گوڈوٹ {0} پورٹ پر سروس دے رہا ہے"
+ webpage.opened: "ETS2LA UI کھل گیا۔"
+ webpage.ui_loading: "براہ کرم انتظار کریں، یوزر انٹرفیس تیار ہو رہا ہے"
+ controls.listener_started: "کنٹرول لسٹنر شروع ہو گیا۔"
+ sounds.missing_sound: "ساؤنڈ پیک '{0}' میں مطلوبہ آواز '{1}' غائب ہے۔"
+ sounds.invalid_file_type: "ساؤنڈ پیک '{0}' میں غیر موزوں فائل ٹائپ '{1}' ہے۔"
+ sounds.sound_not_found_in_soundpack: "آواز '{0}' چلانے کی کوشش کی گئی، لیکن یہ ساؤنڈ پیک '{1}' میں نہیں ملی۔"
+ logging.delete_log_error: "لاگ فائل کو حذف نہیں کیا جا سکا۔"
+ logging.logger_initialized: "لاگر شروع ہو گیا۔"
+ events.vehicle_change.vehicle_change: "گاڑی کی تبدیلی کا پتہ چلا۔"
+ events.vehicle_change.vehicle_change_description: "ہم نے نئی گاڑی کا پتہ لگا لیا ہے۔ براہ کرم کیبن ویو میں F4 دبائیں، سیٹ کی ترتیبات کھولیں، اور اپنا نیا FOV ویلیو درج کریں۔"
+
+ # MARK: Tutorials
+
+ tutorials.main.window_controls: "یہ ونڈو کنٹرول ہیں۔ سب سے بائیں بٹن اضافی آپشنز کے لیے ہے۔ اس پر ماؤس رکھ کر تفصیل دیکھیں!"
+ tutorials.main.slide_area: "آپ ونڈو کو اس علاقے پر کلک کرکے اور گھسیٹ کر حرکت دے سکتے ہیں۔"
+ tutorials.main.sidebar_collapse: "آپ سائڈبار کو دبانے سے بند کر سکتے ہیں اور 'فل سکرین' موڈ میں جا سکتے ہیں۔"
+ tutorials.main.sidebar: "آپ سائڈبار کے ذریعے ایپ کے مختلف صفحات کو آسانی سے نیویگیٹ کر سکتے ہیں۔"
+ tutorials.main.settings: "فی الحال، آپ کو ترتیبات کے صفحے پر جانا چاہیے!"
+ tutorials.settings.static: "یہ وہ ترتیبات ہیں جو پوری ایپ پر اثر انداز ہوتی ہیں۔"
+ tutorials.settings.global: "یہاں آپ عالمی ترتیبات دیکھ سکتے ہیں، جن میں UI کے اختیارات شامل ہیں۔"
+ tutorials.settings.plugin: "یہ تمام پلگ انز کی فہرست ہے جن کی اپنی ترتیبات ہیں۔"
+ tutorials.settings.sdk: "آخری مرحلے میں، SDK سیٹنگز کو کھولیں اور انسٹال کریں، اگر آپ نے پہلے سے نہیں کیا۔"
+
+ # MARK: Plugins
+
+ plugins.adaptivecruisecontrol: "ایڈاپٹیو کروز کنٹرول"
+ plugins.adaptivecruisecontrol.description: "یہ آگے موجود گاڑی کے مطابق رفتار کو کم کرے گا (اگر آبجیکٹ ڈیٹیکشن ماڈل فعال ہے)۔"
+ plugins.map: "نقشہ"
+ plugins.map.description: "نقشے کی شناخت کا پلگ ان۔"
+ plugins.objectdetection: "آبجیکٹ ڈیٹیکشن"
+ plugins.objectdetection.description: "کمپیوٹر وژن کی مدد سے اشیاء کی شناخت کرتا ہے۔"
+ plugins.trafficlightdetection: "ٹریفک سگنل ڈیٹیکشن"
+ plugins.trafficlightdetection.description: "ٹریفک لائٹس کی شناخت کر کے کروز کنٹرول سسٹم سے ہم آہنگ کرتا ہے۔"
+
+ # MARK: About
+
+ about.about: "ہمارے بارے میں"
+ about.description: "ETS2LA ایک پروجیکٹ ہے جو ETS2 اور ATS کے لیے ایک خودکار ڈرائیونگ حل فراہم کرتا ہے۔"
+ about.statistics: "اعداد و شمار"
+ about.statistics.users_online: "آن لائن صارفین:"
+ about.statistics.users_online_value: "{0} صارفین"
+ about.statistics.past_24h: "پچھلے 24 گھنٹوں میں:"
+ about.statistics.past_24h_value: "{0} منفرد صارفین"
+ about.developers: "ڈویلپرز / شراکت دار"
+ about.translation_credits: "ترجمہ کا شکریہ"
+ about.no_credits: "اس زبان کے لیے کوئی کریڈٹ دستیاب نہیں۔"
+ about.support_development: "ترقی کی حمایت کریں"
+ about.kofi_description: "• اگر آپ کو یہ پروجیکٹ پسند آیا اور آپ اس کی مدد کرنا چاہتے ہیں، تو آپ Ko-Fi کے ذریعے عطیہ کر سکتے ہیں۔"