Compare commits

...

3 Commits

Author SHA1 Message Date
sanasol
fb90277be9 Fix Arabic RTL support: correct locale code and CSS syntax
- Rename ar-AR to ar-SA (valid BCP 47 code for Saudi Arabia)
- Fix missing dot in CSS selector: .news-section .news-header
- Add trailing newline to ar-SA.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 23:00:08 +01:00
sanasol
27c220a757 Merge pull request 'Arabic and RTL support added' (#1) from Yugurten/hytale-f2p:develop into develop 2026-02-22 21:58:25 +00:00
Finix
30929ee0da Arabic and RTL support added 2026-02-22 19:25:01 +00:00
4 changed files with 498 additions and 3 deletions

View File

@@ -8,9 +8,10 @@
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap"
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Noto+Sans+Arabic:wght@300;400;500;600;700&display=swap"
rel="stylesheet">
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="style-RTL.css">
</head>
<body class="bg-black text-white overflow-hidden font-sans select-none" tabindex="-1">

View File

@@ -12,9 +12,18 @@ const i18n = (() => {
{ code: 'ru-RU', name: 'Russian (Russia)' },
{ code: 'sv-SE', name: 'Swedish (Sweden)' },
{ code: 'tr-TR', name: 'Turkish (Turkey)' },
{ code: 'id-ID', name: 'Indonesian (Indonesia)' }
{ code: 'id-ID', name: 'Indonesian (Indonesia)' },
{ code: 'ar-SA', name: 'Arabic (Saudi Arabia)' }
];
// RTL languages
const rtlLanguages = ['ar-SA'];
// Check if current language is RTL
function isRTL() {
return rtlLanguages.includes(currentLang);
}
// Load single language file
async function loadLanguage(lang) {
if (translations[lang]) return true;
@@ -73,6 +82,24 @@ const i18n = (() => {
const key = el.getAttribute('data-i18n-title');
el.title = t(key);
});
// Update RTL layout
updateRTL();
}
// Update RTL layout
function updateRTL() {
const html = document.documentElement;
const body = document.body;
if (isRTL()) {
html.setAttribute('dir', 'rtl');
html.setAttribute('lang', currentLang);
body.classList.add('rtl');
} else {
html.removeAttribute('dir');
html.setAttribute('lang', currentLang);
body.classList.remove('rtl');
}
}
// Initialize - load saved language only
@@ -88,7 +115,8 @@ const i18n = (() => {
t,
setLanguage,
getAvailableLanguages: () => availableLanguages,
getCurrentLanguage: () => currentLang
getCurrentLanguage: () => currentLang,
isRTL
};
})();

257
GUI/locales/ar-SA.json Normal file
View File

@@ -0,0 +1,257 @@
{
"nav": {
"play": "لعب",
"mods": "المودات",
"news": "الأخبار",
"chat": "دردشة اللاعبين",
"settings": "الإعدادات"
},
"header": {
"playersLabel": "اللاعبون:",
"manageProfiles": "إدارة الملفات الشخصية",
"defaultProfile": "الافتراضي"
},
"install": {
"title": "مشغل اللعب المجاني",
"playerName": "اسم اللاعب",
"playerNamePlaceholder": "أدخل اسمك",
"gameBranch": "إصدار اللعبة",
"releaseVersion": "إصدار نهائي (مستقر)",
"preReleaseVersion": "إصدار تجريبي (تجريبي)",
"customInstallation": "تثبيت مخصص",
"installationFolder": "مجلد التثبيت",
"pathPlaceholder": "الموقع الافتراضي",
"browse": "تصفح",
"installButton": "تثبيت HYTALE",
"installing": "جاري التثبيت..."
},
"play": {
"ready": "جاهز للعب",
"subtitle": "شغل Hytale وابدأ المغامرة",
"playButton": "لعب HYTALE",
"latestNews": "آخر الأخبار",
"viewAll": "عرض الكل",
"checking": "جاري التحقق...",
"play": "بدء"
},
"mods": {
"searchPlaceholder": "البحث عن مودات...",
"myMods": "موداتي",
"previous": "السابق",
"next": "التالي",
"page": "صفحة",
"of": "من",
"modalTitle": "موداتي",
"noModsFound": "لم يتم العثور على مودات",
"noModsFoundDesc": "حاول تعديل معايير البحث",
"noModsInstalled": "لا توجد مودات مثبتة",
"noModsInstalledDesc": "أضف مودات من CurseForge أو استورد ملفات محلية",
"view": "عرض",
"install": "تثبيت",
"installed": "مثبت",
"enable": "تفعيل",
"disable": "تعطيل",
"active": "نشط",
"disabled": "معطل",
"delete": "حذف المود",
"noDescription": "لا يوجد وصف متاح",
"confirmDelete": "هل أنت متأكد أنك تريد حذف \"{name}\"؟",
"confirmDeleteDesc": "لا يمكن التراجع عن هذا الإجراء.",
"confirmDeletion": "تأكيد الحذف",
"apiKeyRequired": "مطلوب مفتاح API",
"apiKeyRequiredDesc": "مطلوب مفتاح CurseForge API لتصفح المودات"
},
"news": {
"title": "كل الأخبار",
"readMore": "اقرأ المزيد"
},
"chat": {
"title": "دردشة اللاعبين",
"pickColor": "اللون",
"inputPlaceholder": "اكتب رسالتك...",
"send": "إرسال",
"online": "متصل",
"charCounter": "{current}/{max}",
"secureChat": "دردشة آمنة - الروابط محجوبة",
"joinChat": "انضمام للدردشة",
"chooseUsername": "اختر اسم مستخدم للانضمام إلى دردشة اللاعبين",
"username": "اسم المستخدم",
"usernamePlaceholder": "أدخل اسم المستخدم...",
"usernameHint": "3-20 حرفاً، حروف، أرقام، و - و _ فقط",
"joinButton": "انضمام",
"colorModal": {
"title": "تخصيص لون اسم المستخدم",
"chooseSolid": "اختر لوناً ثابتاً:",
"customColor": "لون مخصص:",
"preview": "معاينة:",
"previewUsername": "اسم المستخدم",
"apply": "تطبيق اللون"
}
},
"settings": {
"title": "الإعدادات",
"java": "بيئة تشغيل جافا",
"useCustomJava": "استخدام مسار جافا مخصص",
"javaDescription": "تجاوز بيئة جافا المرفقة واستخدام تثبيت خاص بك",
"javaPath": "مسار ملف جافا التنفيذي",
"javaPathPlaceholder": "اختر مسار جافا...",
"javaBrowse": "تصفح",
"javaHint": "اختر مجلد تثبيت جافا (يدعم ويندوز، ماك، ولينكس)",
"discord": "تكامل ديسكورد",
"enableRPC": "تفعيل نشاط ديسكورد (Rich Presence)",
"discordDescription": "إظهار نشاط المشغل الخاص بك على ديسكورد",
"game": "خيارات اللعبة",
"playerName": "اسم اللاعب",
"playerNamePlaceholder": "أدخل اسم اللاعب",
"playerNameHint": "سيتم استخدام هذا الاسم داخل اللعبة (1-16 حرفاً)",
"openGameLocation": "فتح موقع اللعبة",
"openGameLocationDesc": "فتح مجلد تثبيت اللعبة",
"account": "إدارة UUID اللاعب",
"currentUUID": "الـ UUID الحالي",
"uuidPlaceholder": "جاري تحميل UUID...",
"copyUUID": "نسخ UUID",
"regenerateUUID": "إعادة إنشاء UUID",
"uuidHint": "معرف اللاعب الفريد الخاص بك لهذا الاسم",
"manageUUIDs": "إدارة جميع الـ UUIDs",
"manageUUIDsDesc": "عرض وإدارة جميع معرفات اللاعبين",
"language": "اللغة",
"selectLanguage": "اختر اللغة",
"repairGame": "إصلاح اللعبة",
"reinstallGame": "إعادة تثبيت ملفات اللعبة (يحفظ البيانات)",
"gpuPreference": "تفضيل معالج الرسوميات (GPU)",
"gpuHint": "ميزة للمحمول فقط؛ اضبطها على Integrated إذا كنت تستخدم كمبيوتر مكتبي",
"gpuAuto": "تلقائي",
"gpuIntegrated": "مدمج",
"gpuDedicated": "منفصل",
"logs": "سجلات النظام",
"logsCopy": "نسخ",
"logsRefresh": "تحديث",
"logsFolder": "فتح المجلد",
"logsLoading": "جاري تحميل السجلات...",
"closeLauncher": "سلوك المشغل",
"closeOnStart": "إغلاق المشغل عند بدء اللعبة",
"closeOnStartDescription": "إغلاق المشغل تلقائياً بعد تشغيل Hytale",
"hwAccel": "تسريع الأجهزة (Hardware Acceleration)",
"hwAccelDescription": "تفعيل تسريع الأجهزة للمشغل",
"gameBranch": "فرع اللعبة",
"branchRelease": "إصدار نهائي",
"branchPreRelease": "إصدار تجريبي",
"branchHint": "التبديل بين الإصدار المستقر والإصدار التجريبي",
"branchWarning": "تغيير الفرع سيؤدي إلى تحميل وتثبيت نسخة مختلفة من اللعبة",
"branchSwitching": "جاري التبديل إلى {branch}...",
"branchSwitched": "تم التبديل إلى {branch} بنجاح!",
"installRequired": "التثبيت مطلوب",
"branchInstallConfirm": "سيتم تثبيت اللعبة لفرع {branch}. هل تريد الاستمرار؟"
},
"uuid": {
"modalTitle": "إدارة UUID",
"currentUserUUID": "UUID المستخدم الحالي",
"allPlayerUUIDs": "جميع معرفات UUID للاعبين",
"generateNew": "إنشاء UUID جديد",
"loadingUUIDs": "جاري تحميل الـ UUIDs...",
"setCustomUUID": "تعيين UUID مخصص",
"customPlaceholder": "أدخل UUID مخصص (الصيغة: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)",
"setUUID": "تعيين UUID",
"warning": "تحذير: تعيين UUID مخصص سيغير هوية اللاعب الحالية",
"copyTooltip": "نسخ UUID",
"regenerateTooltip": "إنشاء UUID جديد"
},
"profiles": {
"modalTitle": "إدارة الملفات الشخصية",
"newProfilePlaceholder": "اسم الملف الشخصي الجديد",
"createProfile": "إنشاء ملف شخصي"
},
"discord": {
"notificationText": "انضم إلى مجتمعنا على ديسكورد!",
"joinButton": "انضم إلى ديسكورد"
},
"common": {
"confirm": "تأكيد",
"cancel": "إلغاء",
"save": "حفظ",
"close": "إغلاق",
"delete": "حذف",
"edit": "تعديل",
"loading": "جاري التحميل...",
"apply": "تطبيق",
"install": "تثبيت"
},
"notifications": {
"gameDataNotFound": "خطأ: لم يتم العثور على بيانات اللعبة",
"gameUpdatedSuccess": "تم تحديث اللعبة بنجاح! 🎉",
"updateFailed": "فشل التحديث: {error}",
"updateError": "خطأ في التحديث: {error}",
"discordEnabled": "تم تفعيل نشاط ديسكورد",
"discordDisabled": "تم تعطيل نشاط ديسكورد",
"discordSaveFailed": "فشل حفظ إعدادات ديسكورد",
"playerNameRequired": "يرجى إدخال اسم لاعب صالح",
"playerNameSaved": "تم حفظ اسم اللاعب بنجاح",
"playerNameSaveFailed": "فشل حفظ اسم اللاعب",
"uuidCopied": "تم نسخ الـ UUID إلى الحافظة!",
"uuidCopyFailed": "فشل نسخ الـ UUID",
"uuidRegenNotAvailable": "إعادة إنشاء UUID غير متاحة",
"uuidRegenFailed": "فشل إعادة إنشاء الـ UUID",
"uuidGenerated": "تم إنشاء UUID جديد بنجاح!",
"uuidGeneratedShort": "تم إنشاء UUID جديد!",
"uuidGenerateFailed": "فشل إنشاء UUID جديد",
"uuidRequired": "يرجى إدخال UUID",
"uuidInvalidFormat": "صيغة UUID غير صالحة",
"uuidSetFailed": "فشل تعيين الـ UUID المخصص",
"uuidSetSuccess": "تم تعيين الـ UUID المخصص بنجاح!",
"uuidDeleteFailed": "فشل حذف الـ UUID",
"uuidDeleteSuccess": "تم حذف الـ UUID بنجاح!",
"modsDownloading": "جاري تحميل {name}...",
"modsTogglingMod": "جاري تبديل حالة المود...",
"modsDeletingMod": "جاري حذف المود...",
"modsLoadingMods": "جاري تحميل المودات من CurseForge...",
"modsInstalledSuccess": "تم تثبيت {name} بنجاح! 🎉",
"modsDeletedSuccess": "تم حذف {name} بنجاح",
"modsDownloadFailed": "فشل تحميل المود: {error}",
"modsToggleFailed": "فشل تبديل المود: {error}",
"modsDeleteFailed": "فشل حذف المود: {error}",
"modsModNotFound": "لم يتم العثور على معلومات المود",
"hwAccelSaved": "تم حفظ إعداد تسريع الأجهزة",
"hwAccelSaveFailed": "فشل حفظ إعداد تسريع الأجهزة",
"noUsername": "لم يتم تهيئة اسم مستخدم. يرجى حفظ اسم المستخدم أولاً.",
"switchUsernameSuccess": "تم التبديل إلى المستخدم \"{username}\" بنجاح!",
"switchUsernameFailed": "فشل تبديل اسم المستخدم",
"playerNameTooLong": "يجب أن يكون اسم اللاعب 16 حرفاً أو أقل"
},
"confirm": {
"defaultTitle": "تأكيد الإجراء",
"regenerateUuidTitle": "إنشاء UUID جديد",
"regenerateUuidMessage": "هل أنت متأكد أنك تريد إنشاء UUID جديد؟ سيؤدي ذلك إلى تغيير هوية اللاعب الخاصة بك.",
"regenerateUuidButton": "إنشاء",
"setCustomUuidTitle": "تعيين UUID مخصص",
"setCustomUuidMessage": "هل أنت متأكد أنك تريد تعيين هذا الـ UUID المخصص؟ سيؤدي ذلك إلى تغيير هوية اللاعب الخاصة بك.",
"setCustomUuidButton": "تعيين UUID",
"deleteUuidTitle": "حذف UUID",
"deleteUuidMessage": "هل أنت متأكد أنك تريد حذف الـ UUID الخاص بـ \"{username}\"؟ لا يمكن التراجع عن هذا الإجراء.",
"deleteUuidButton": "حذف",
"uninstallGameTitle": "إلغاء تثبيت اللعبة",
"uninstallGameMessage": "هل أنت متأكد أنك تريد إلغاء تثبيت Hytale؟ سيتم حذف جميع ملفات اللعبة.",
"uninstallGameButton": "إلغاء التثبيت",
"switchUsernameTitle": "تبديل الهوية",
"switchUsernameMessage": "التبديل إلى اسم المستخدم \"{username}\"؟ سيؤدي هذا إلى تغيير هوية اللاعب الحالية.",
"switchUsernameButton": "تبديل"
},
"progress": {
"initializing": "جاري التهيئة...",
"downloading": "جاري التحميل...",
"installing": "جاري التثبيت...",
"extracting": "جاري الاستخراج...",
"verifying": "جاري التحقق...",
"switchingProfile": "جاري تبديل الملف الشخصي...",
"profileSwitched": "تم تبديل الملف الشخصي!",
"startingGame": "جاري بدء اللعبة...",
"launching": "جاري التشغيل...",
"uninstallingGame": "جاري إلغاء تثبيت اللعبة...",
"gameUninstalled": "تم إلغاء تثبيت اللعبة بنجاح!",
"uninstallFailed": "فشل إلغاء التثبيت: {error}",
"startingUpdate": "جاري بدء تحديث اللعبة الإجباري...",
"installationComplete": "تم اكتمال التثبيت بنجاح!",
"installationFailed": "فشل التثبيت: {error}",
"installingGameFiles": "جاري تثبيت ملفات اللعبة...",
"installComplete": "اكتمل التثبيت!"
}
}

209
GUI/style-RTL.css Normal file
View File

@@ -0,0 +1,209 @@
body.rtl {
direction: rtl;
font-family: 'Noto Sans Arabic', 'Space Grotesk', sans-serif;
}
body.rtl .sidebar {
right: 0;
left: auto;
border-right: none;
border-left: 1px solid rgba(255, 255, 255, 0.1);
}
body.rtl .nav-item.active::before {
right: -8px;
left: auto;
border-radius: 4px 0 0 4px;
}
body.rtl .nav-tooltip {
right: 100%;
left: auto;
margin-right: 0.5rem;
margin-left: 0;
}
body.rtl .nav-item:hover .nav-tooltip {
transform: translateX(-8px);
}
body.rtl .main-content {
margin-right: 80px;
margin-left: 0;
}
/* Header Layout*/
body.rtl .players-counter {
order: 2;
margin-left: 1.5rem;
margin-right: 0;
}
body.rtl .profile-selector {
order: -1;
}
body.rtl .window-controls {
order: 3;
flex-direction: row;
}
body.rtl .profile-dropdown {
right: auto;
left: 0;
}
body.rtl .form-group {
text-align: right;
}
body.rtl .radio-label,
body.rtl .checkbox-group {
flex-direction: row-reverse;
}
body.rtl .form-input {
border-radius: 0 8px 8px 0;
}
body.rtl .mods-pagination {
flex-direction: row-reverse;
}
body.rtl .pagination-btn:first-child i {
transform: rotate(180deg);
}
body.rtl .pagination-btn:last-child i {
transform: rotate(180deg);
}
/* UUID Display */
body.rtl .uuid-display-container {
flex-direction: row-reverse;
}
body.rtl .uuid-btn {
border-radius: 0 8px 8px 0;
}
body.rtl .uuid-input {
border-radius: 8px 0 0 8px;
}
body.rtl .segmented-control {
flex-direction: row-reverse;
}
/* Mod Grid Layout */
body.rtl .mods-search {
text-align: right;
}
body.rtl .mods-search-container {
flex-direction: row-reverse;
}
body.rtl .mods-actions {
order: -1;
}
body.rtl .mod-card {
direction: rtl;
}
body.rtl .installed-mod-card {
direction: rtl;
}
body.rtl .installed-mod-card .mod-info {
text-align: right;
}
body.rtl .mods-header {
flex-direction: row-reverse;
}
body.rtl .news-section .news-header {
flex-direction: row-reverse;
}
/* Settings Layout */
body.rtl .settings-option {
text-align: right;
}
body.rtl .settings-input-group {
text-align: right;
}
body.rtl .settings-input {
border-radius: 0 8px 8px 0;
}
body.rtl .settings-section-title i {
margin-right: 0;
margin-left: 0.5rem;
}
body.rtl .settings-hint i {
margin-right: 0;
margin-left: 0.5rem;
}
body.rtl .custom-options,
body.rtl .custom-java-options {
text-align: right;
}
body.rtl .checkbox-content {
margin-right: 2rem;
margin-left: 0;
}
body.rtl .btn-content {
text-align: right;
}
/* Icons & Transformations */
body.rtl .news-title i {
padding-left: 0.5rem;
}
body.rtl .uuid-modal-title i {
padding-left: 0.5rem;
}
body.rtl .mods-modal-title i {
padding-left: 0.5rem;
}
body.rtl .view-all-btn i,
body.rtl .sidebar-nav div i,
body.rtl .logs-header i,
body.rtl .home-play-button i {
transform: scaleX(-1);
}
body.rtl .play-title i {
transform: scaleX(-1);
padding-right: 0.5rem;
}
body.rtl .logs-terminal {
direction: ltr;
text-align: left;
}
body.rtl .version-display-bottom {
right: auto;
left: 1rem;
}