From aab82966190e59036be7839603800e49712d21ae Mon Sep 17 00:00:00 2001 From: r4sas Date: Sun, 18 May 2025 02:20:31 +0300 Subject: [PATCH] [i18n] add Hebrew and Hindi translations, add rtl support (testing) Signed-off-by: r4sas --- daemon/HTTPServer.cpp | 11 +- i18n/Afrikaans.cpp | 5 +- i18n/Armenian.cpp | 5 +- i18n/Chinese.cpp | 5 +- i18n/Czech.cpp | 5 +- i18n/English.cpp | 5 +- i18n/French.cpp | 7 +- i18n/German.cpp | 5 +- i18n/Hebrew.cpp | 202 +++++++++++++++++++++++++++++++++++++ i18n/Hindi.cpp | 226 ++++++++++++++++++++++++++++++++++++++++++ i18n/I18N.h | 11 +- i18n/I18N_langs.h | 6 +- i18n/Italian.cpp | 5 +- i18n/Polish.cpp | 5 +- i18n/Portuguese.cpp | 5 +- i18n/Russian.cpp | 5 +- i18n/Spanish.cpp | 5 +- i18n/Swedish.cpp | 5 +- i18n/Turkish.cpp | 5 +- i18n/Turkmen.cpp | 5 +- i18n/Ukrainian.cpp | 5 +- i18n/Uzbek.cpp | 5 +- 22 files changed, 518 insertions(+), 25 deletions(-) create mode 100644 i18n/Hebrew.cpp create mode 100644 i18n/Hindi.cpp diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index dca545fe..be1ec4ac 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -134,7 +134,7 @@ namespace http { { std::string state; std::string_view stateText; - switch (eState) + switch (eState) { case i2p::tunnel::eTunnelStateBuildReplyReceived : case i2p::tunnel::eTunnelStatePending : state = "building"; break; @@ -146,7 +146,7 @@ namespace http { default: state = "unknown"; break; } if (stateText.empty ()) stateText = tr(state); - + s << " " << stateText << ((explr) ? " (" + std::string(tr("exploratory")) + ")" : "") << ", "; // TODO: ShowTraffic(s, bytes); s << "\r\n"; @@ -172,9 +172,12 @@ namespace http { auto it = i2p::i18n::languages.find(currLang); std::string langCode = it->second.ShortCode; + // Right to Left language option + bool rtl = i2p::client::context.GetLanguage ()->GetRTL(); + s << "\r\n" - "\r\n" + "\r\n" " \r\n" /* TODO: Find something to parse html/template system. This is horrible. */ " \r\n" " \r\n" @@ -1479,7 +1482,7 @@ namespace http { reply.body = content; m_SendBuffer = reply.to_string(); - boost::asio::async_write (*m_Socket, boost::asio::buffer(m_SendBuffer), boost::asio::transfer_all (), + boost::asio::async_write (*m_Socket, boost::asio::buffer(m_SendBuffer), boost::asio::transfer_all (), std::bind (&HTTPConnection::Terminate, shared_from_this (), std::placeholders::_1)); } diff --git a/i18n/Afrikaans.cpp b/i18n/Afrikaans.cpp index b69c42ef..0afa086f 100644 --- a/i18n/Afrikaans.cpp +++ b/i18n/Afrikaans.cpp @@ -29,6 +29,9 @@ namespace afrikaans // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"failed", "Het misluk"}, @@ -73,7 +76,7 @@ namespace afrikaans // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Armenian.cpp b/i18n/Armenian.cpp index 67955d8a..af22d0d9 100644 --- a/i18n/Armenian.cpp +++ b/i18n/Armenian.cpp @@ -29,6 +29,9 @@ namespace armenian // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f ԿիԲ"}, @@ -196,7 +199,7 @@ namespace armenian // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Chinese.cpp b/i18n/Chinese.cpp index e3b63ebd..f439bb67 100644 --- a/i18n/Chinese.cpp +++ b/i18n/Chinese.cpp @@ -29,6 +29,9 @@ namespace chinese // language namespace return 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace chinese // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Czech.cpp b/i18n/Czech.cpp index 94803354..c9697f41 100644 --- a/i18n/Czech.cpp +++ b/i18n/Czech.cpp @@ -29,6 +29,9 @@ namespace czech // language namespace return (n == 1) ? 0 : (n >= 2 && n <= 4) ? 1 : 2; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace czech // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/English.cpp b/i18n/English.cpp index fb774527..eb7067e2 100644 --- a/i18n/English.cpp +++ b/i18n/English.cpp @@ -30,6 +30,9 @@ namespace english // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"", ""}, @@ -42,7 +45,7 @@ namespace english // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/French.cpp b/i18n/French.cpp index 985296a3..2618772f 100644 --- a/i18n/French.cpp +++ b/i18n/French.cpp @@ -29,6 +29,9 @@ namespace french // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f Kio"}, @@ -44,7 +47,7 @@ namespace french // language namespace {"i2pd webconsole", "Console web i2pd"}, {"Main page", "Page principale"}, {"Router commands", "Commandes du routeur"}, - {"Local Destinations", "Destinations locales"}, + {"Local Destinations", "Destinatioans localeAlger"}, {"LeaseSets", "Jeu de baux"}, {"Tunnels", "Tunnels"}, {"Transit Tunnels", "Tunnels transitoires"}, @@ -215,7 +218,7 @@ namespace french // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/German.cpp b/i18n/German.cpp index 90ce82f4..b3b35e99 100644 --- a/i18n/German.cpp +++ b/i18n/German.cpp @@ -29,6 +29,9 @@ namespace german // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -210,7 +213,7 @@ namespace german // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Hebrew.cpp b/i18n/Hebrew.cpp new file mode 100644 index 00000000..7e56395f --- /dev/null +++ b/i18n/Hebrew.cpp @@ -0,0 +1,202 @@ +/* +* Copyright (c) 2025, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include "I18N.h" + +// Hebrew localization file + +namespace i2p +{ +namespace i18n +{ +namespace hebrew // language namespace +{ + // language name in lowercase + static std::string language = "hebrew"; + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3; + } + + // Right to Left language? + static bool rtl = true; + + static const LocaleStrings strings + { + {"%.2f KiB", "%.2f קי״ב"}, + {"%.2f MiB", "%.2f מי״ב"}, + {"%.2f GiB", "%.2f קי״ב"}, + {"Purple I2P Webconsole", "קונסולת Purple I2P"}, + {"i2pd webconsole", "קונסולת i2pd"}, + {"Main page", "עמוד ראשי"}, + {"Router commands", "פקודות נתב"}, + {"Local Destinations", "יעדים מקומיים"}, + {"Tunnels", "מנהרות"}, + {"Transit Tunnels", "מנהרות מעבר"}, + {"Transports", "מובילים"}, + {"I2P tunnels", "מנהרות I2P"}, + {"SAM sessions", "הפעלות SAM"}, + {"Unknown", "לא מוכר"}, + {"Proxy", "פרוקסי"}, + {"Mesh", "סיבוך"}, + {"Clock skew", "לכסון שעון"}, + {"Offline", "לא מקוון"}, + {"Symmetric NAT", "NAT סימטרי"}, + {"Full cone NAT", "NAT חסום לחלוטין"}, + {"No Descriptors", "אין מתארים"}, + {"Uptime", "זמן הפעלה"}, + {"Network status", "מצב רשת תקשורת"}, + {"Network status v6", "מצב רשת תקשורת v6"}, + {"Stopping in", "מפסיק בעוד"}, + {"Family", "משפחה"}, + {"Tunnel creation success rate", "שיעור הצלחה של יצירת מנהרות"}, + {"Total tunnel creation success rate", "שיעור הצלחה כולל של יצירת מנהרות"}, + {"Received", "נתקבל"}, + {"%.2f KiB/s", "%.2f קי״ב/ש"}, + {"Sent", "נשלח"}, + {"Transit", "מעבר"}, + {"Data path", "נתיב מידע"}, + {"Hidden content. Press on text to see.", "תוכן מוסתר. לחץ על הטקסט כדי לראותו."}, + {"Router Ident", "מזהה נתב"}, + {"Router Family", "משפחת נתב"}, + {"Version", "גרסא"}, + {"Our external address", "הכתובת החיצונית שלנו"}, + {"supported", "נתמך"}, + {"Routers", "נתבים"}, + {"Client Tunnels", "מנהרות לקוח"}, + {"Services", "שירותים"}, + {"Enabled", "מאופשר"}, + {"Disabled", "מנוטרל"}, + {"Encrypted B33 address", "כתובת B33 מוצפנת"}, + {"Address registration line", "שורת רישום כתובת"}, + {"Domain", "תחום"}, + {"Generate", "צור"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "הערה מחרוזת תוצאה יכולה להיות מועילה רק לצורך רישום תחומים 2LD (example.i2p). לשם רישום תתי-תחום עליך להיוועץ עם i2pd-tools."}, + {"Address", "כתובת"}, + {"Type", "טיפוס"}, + {"Expire LeaseSet", "פקיעת LeaseSet"}, + {"Inbound tunnels", "מנהרות פנימיות"}, + {"%dms", "מילישניות %d"}, + {"Outbound tunnels", "מנהרות חיצוניות"}, + {"Tags", "תוויות"}, + {"Incoming", "נכנס"}, + {"Outgoing", "יוצא"}, + {"Destination", "יעד"}, + {"Amount", "כמות"}, + {"Incoming Tags", "תוויות נכנסות"}, + {"Tags sessions", "הפעלות תוויות"}, + {"Status", "מצב"}, + {"Local Destination", "יעד מקומי"}, + {"Streams", "זרמים"}, + {"Close stream", "סגור זרם"}, + {"Such destination is not found", "יעד כזה לא נמצא"}, + {"I2CP session not found", "הפעלת I2CP לא נמצאה"}, + {"I2CP is not enabled", "I2CP לא מאופשר"}, + {"Invalid", "לא תקין"}, + {"Store type", "טיפוס אחסון"}, + {"Expires", "פוקע"}, + {"Non Expired Leases", "חכירות בלתי פקיעות"}, + {"Gateway", "שער-דרך"}, + {"TunnelID", "מזהה מנהרה"}, + {"EndDate", "תאריך סיום"}, + {"floodfill mode is disabled", "מצב floodfill הינו מנוטרל"}, + {"Queue size", "גודל תור"}, + {"Run peer test", "הרץ בדיקת עמית"}, + {"Reload tunnels configuration", "טען מחדש תצורת מנהרות"}, + {"Decline transit tunnels", "דחה מנהרות מעבר"}, + {"Accept transit tunnels", "קבל מנהרות מעבר"}, + {"Cancel graceful shutdown", "בטל כיבוי עדין"}, + {"Start graceful shutdown", "התחל כיבוי עדין"}, + {"Force shutdown", "כפה כיבוי"}, + {"Reload external CSS styles", "טען מחדש סגנונות CSS חיצוניים"}, + {"Note: any action done here are not persistent and not changes your config files.", "הערה כל פעולה אשר מבוצעת כאן אינה המשכית ולא משנה את קובצי התצורה שלך."}, + {"Logging level", "דרגת רישום יומן"}, + {"Transit tunnels limit", "מגבלת מנהרות מעבר"}, + {"Change", "שנה"}, + {"Change language", "שנה שפה"}, + {"no transit tunnels currently built", "אין מנהרות מעבר אשר בנויות כעת"}, + {"SAM disabled", "SAM מנוטרל"}, + {"no sessions currently running", "אין הפעלה אשר מורצת כעת"}, + {"SAM session not found", "הפעלת SAM לא נמצאה"}, + {"SAM Session", "הפעלת SAM"}, + {"Server Tunnels", "מנהרות שרת"}, + {"Unknown page", "עמוד לא מוכר"}, + {"Invalid token", "סימן לא תקין"}, + {"SUCCESS", "הצלחה"}, + {"Stream closed", "זרם סגור"}, + {"Stream not found or already was closed", "זרם לא נמצא או שהוא היה כבר סגור"}, + {"Destination not found", "יעד לא נמצא"}, + {"StreamID can't be null", "מזהה זרם (StreamID) לא יכול להיות אפסי"}, + {"Return to destination page", "חזור לעמוד יעד"}, + {"You will be redirected in %d seconds", "אתה תכוון מחדש בעוד %d שניות"}, + {"LeaseSet expiration time updated", "זמן פקיעה של LeaseSet עודכן"}, + {"LeaseSet is not found or already expired", "LeaseSet אינו נמצא או שהוא כבר פקע"}, + {"Transit tunnels count must not exceed %d", "אסור לספירת מנהרות מעבר לעלות על %d"}, + {"Back to commands list", "חזור לרשימת פקודות"}, + {"Register at reg.i2p", "הירשם באתר reg.i2p"}, + {"Description", "תיאור"}, + {"A bit information about service on domain", "מידע אודות שירות על תחום"}, + {"Submit", "שלח"}, + {"Domain can't end with .b32.i2p", "תחום לא יכול להסתיים עם ‎.b32.i2p"}, + {"Domain must end with .i2p", "תחום חייב להסתיים עם ‎.i2p"}, + {"Unknown command", "פקודה לא מוכרת"}, + {"Command accepted", "פקודה נתקבלה"}, + {"Proxy error", "שגיאת פרוקסי"}, + {"Proxy info", "מידע פרוקסי"}, + {"Proxy error: Host not found", "שגיאת פרוקסי: מארח לא נמצא"}, + {"Remote host not found in router's addressbook", "ארח מרוחק לא נמצא בתוך הפנקס כתובות של הנתב"}, + {"You may try to find this host on jump services below", "באפשרותך לנסות למצוא את מארח זה דרך שירותי קפיצה להלן"}, + {"Invalid request", "בקשה לא תקינה"}, + {"Proxy unable to parse your request", "פרוקסי לא מסוגל לנתח את בקשתך"}, + {"Addresshelper is not supported", "סייען-כתובות אינו נתמך"}, + {"Host %s is already in router's addressbook. Be careful: source of this URL may be harmful! Click here to update record: Continue.", "מארח %s is כבר נמצא בפנקס כתובות של הנתב. זהירות: מקור URL זה עלול להזיק! לחץ כאן כדי לעדכן מרשם: המשך."}, + {"Addresshelper forced update rejected", "אילוץ עדכון של סייען-כתובות נדחה"}, + {"To add host %s in router's addressbook, click here: Continue.", "Tכדי להוסיף את מארח %s לפנקס כתובות של הנתב: המשך."}, + {"Addresshelper request", "בקשת סייען-כתובות"}, + {"Host %s added to router's addressbook from helper. Click here to proceed: Continue.", "מארח %s נתווסף לסייען-כתובות של הנתב דרך סייען. לחץ כאן כדי proceed: המשך."}, + {"Addresshelper adding", "הוספת סייען-כתובות"}, + {"Host %s is already in router's addressbook. Click here to update record: Continue.", "מארח %s כבר נמצא בספר כתובות של הנתב. לחץ כאן כדי לעדכן מרשם: המשך."}, + {"Addresshelper update", "עדכון סייען-כתובות"}, + {"Invalid request URI", "בקשת URI לא תקינה"}, + {"Can't detect destination host from request", "לא יכול לאתר יעד מארח מתוך בקשה"}, + {"Host %s is not inside I2P network, but outproxy is not enabled", "מארח %s לא נמצא בתוך רשת I2P, אולם outproxy אינו מאופשר"}, + {"Hostname is too long", "שם-מארח הינו ארוך מדי"}, + {"Cannot negotiate with SOCKS proxy", "לא מסוגל להסדיר פרוקסי SOCKS"}, + {"CONNECT error", "שגיאת חיבור"}, + {"Failed to connect", "נכשל להתחבר"}, + {"SOCKS proxy error", "שגיאת פרוקסי SOCKS"}, + {"No reply from SOCKS proxy", "אין מענה מתוך פרוקסי SOCKS"}, + {"Cannot connect", "לא מסוגל להתחבר"}, + {"Host is down", "מארח הינו מושבת"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "לא יכול ליצור חיבור למארח מבוקש, המארח עשוי להיות מושבת. אנא נסה שוב מאוחר יותר."}, + {"", ""}, + }; + + static std::map> plurals + { + {"%d days", {"יום %d", "יומיים", "ימים %d", "ימים %d"}}, + {"%d hours", {"שעה %d", "שעתיים", "שעות %d", "שעות %d"}}, + {"%d minutes", {"דקה %d", "שתי דקות", "דקות %d", "דקות %d"}}, + {"%d seconds", {"שניה %d", "שתי שניות", "שניות %d", "שניות %d"}}, + {"", {"", "", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p diff --git a/i18n/Hindi.cpp b/i18n/Hindi.cpp new file mode 100644 index 00000000..7ce9b65b --- /dev/null +++ b/i18n/Hindi.cpp @@ -0,0 +1,226 @@ +/* +* Copyright (c) 2025, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include "I18N.h" + +// Hindi localization file + +namespace i2p +{ +namespace i18n +{ +namespace hindi // language namespace +{ + // language name in lowercase + static std::string language = "hindi"; + + // See for language plural forms here: + // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html + static int plural (int n) { + return n != 1 ? 1 : 0; + } + + // Right to Left language? + static bool rtl = false; + + static const LocaleStrings strings + { + {"%.2f KiB", "%.2f कीबी"}, + {"%.2f MiB", "%.2f मीबी"}, + {"%.2f GiB", "%.2f जीबी"}, + {"building", "निर्माण"}, + {"failed", "विफल"}, + {"expiring", "समाप्त होना"}, + {"established", "स्थापित"}, + {"unknown", "अज्ञात"}, + {"exploratory", "अन्वेषणात्मक"}, + {"Purple I2P Webconsole", "पर्पल I2P वेब कंसोल"}, + {"i2pd webconsole", "i2pd वेब कंसोल"}, + {"Main page", "मुख्य पृष्ठ"}, + {"Router commands", "राउटर आदेश"}, + {"Local Destinations", "स्थानीय गंतव्य"}, + {"LeaseSets", "पट्ट समुच्चय"}, + {"Tunnels", "सुरंग"}, + {"Transit Tunnels", "संचरण सुरंगें"}, + {"Transports", "परिवहन"}, + {"I2P tunnels", "I2P सुरंगें"}, + {"SAM sessions", "SAM सत्र"}, + {"ERROR", "त्रुटि"}, + {"OK", "ठीक है"}, + {"Testing", "परीक्षण"}, + {"Firewalled", "फायरवॉल"}, + {"Unknown", "अज्ञात"}, + {"Proxy", "प्रॉक्सी"}, + {"Mesh", "जाली"}, + {"Clock skew", "घड़ी संकेत विचलन"}, + {"Offline", "ऑफलाइन"}, + {"Symmetric NAT", "सममितीय NAT"}, + {"Full cone NAT", "पूर्णकोण NAT"}, + {"No Descriptors", "कोई वर्णनकर्त्तृ नहीं हैं"}, + {"Uptime", "संचालन समय"}, + {"Network status", "संपर्क स्थिति"}, + {"Network status v6", "संपर्क स्थिति v6"}, + {"Stopping in", "में अवसान प्रारंभ हो रहा है"}, + {"Family", "परिवार"}, + {"Tunnel creation success rate", "सुरंग निर्माण सफलता दर"}, + {"Total tunnel creation success rate", "कुल सुरंग निर्माण सफलता दर"}, + {"Received", "प्राप्त हुआ"}, + {"%.2f KiB/s", "%.2f कीबी/से"}, + {"Sent", "प्रेषित"}, + {"Transit", "संचरण"}, + {"Data path", "डेटा पथ"}, + {"Hidden content. Press on text to see.", "सामग्री छिपाई गई है। देखने हेतु पाठ पर दबाएँ।"}, + {"Router Ident", "राउटर परिचय"}, + {"Router Family", "राउटर परिवार"}, + {"Router Caps", "राउटर कैप्स"}, + {"Version", "संस्करण"}, + {"Our external address", "हमारा बाह्य पता"}, + {"supported", "समर्थित"}, + {"Routers", "राउटर"}, + {"Floodfills", "पूर्णक संवाहक"}, + {"Client Tunnels", "क्लाइंट सुरंगें"}, + {"Services", "सेवाएँ"}, + {"Enabled", "सक्षम है"}, + {"Disabled", "निष्क्रिय है"}, + {"Encrypted B33 address", "कूटलिखित B33 पता"}, + {"Address registration line", "पता पंजीकरण पंक्ति"}, + {"Domain", "डोमेन"}, + {"Generate", "सृजित करें"}, + {"Note: result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "नोट: परिणाम स्ट्रिंग का उपयोग केवल 2LD डोमेनों (जैसे example.i2p) को रजिस्टर करने के लिए किया जा सकता है। सबडोमेन रजिस्टर करने के लिए कृपया i2pd-tools का उपयोग करें।"}, + {"Address", "पता"}, + {"Type", "प्रकार"}, + {"EncType", "कूट प्रकार"}, + {"Expire LeaseSet", "पट्ट समुच्चय का अवसान करें"}, + {"Inbound tunnels", "आगमनशील सुरंगें"}, + {"%dms", "%dms"}, + {"Outbound tunnels", "प्रस्थानशील सुरंगें"}, + {"Tags", "चिन्हित"}, + {"Incoming", "आगामी"}, + {"Outgoing", "निर्गामी"}, + {"Destination", "गंतव्य"}, + {"Amount", "मात्रा"}, + {"Incoming Tags", "आगामी चिन्हित"}, + {"Tags sessions", "चिन्हित सत्र OR सत्र को चिन्हित करें"}, + {"Status", "स्थिति"}, + {"Local Destination", "स्थानीय गंतव्य"}, + {"Streams", "धाराएँ"}, + {"Close stream", "प्रवाह समाप्त करें"}, + {"Such destination is not found", "ऐसा गंतव्य नहीं मिला"}, + {"I2CP session not found", "I2CP सत्र नहीं मिला"}, + {"I2CP is not enabled", "I2CP निष्क्रिय है"}, + {"Invalid", "अमान्य"}, + {"Store type", "भण्डारगार का प्रकार"}, + {"Expires", "अवसान होता है"}, + {"Non Expired Leases", "अनवसित पट्ट"}, + {"Gateway", "प्रवेशद्वार"}, + {"TunnelID", "सुरंग ID"}, + {"EndDate", "समाप्ति तिथि"}, + {"floodfill mode is disabled", "पूर्णक संवाहक विधि निष्क्रिय है"}, + {"Queue size", "क्यू आकार"}, + {"Run peer test", "सहकर्मी परीक्षण चलाएँ"}, + {"Reload tunnels configuration", "सुरंग विन्यास पुनः लोड करें"}, + {"Decline transit tunnels", "संचरण सुरंगों को अस्वीकार करें"}, + {"Accept transit tunnels", "संचरण सुरंगों को स्वीकार करें"}, + {"Cancel graceful shutdown", "सौम्य अवसान निरस्त करें"}, + {"Start graceful shutdown", "सौम्य समापन प्रारंभ करें"}, + {"Force shutdown", "बाध्य अवसान"}, + {"Reload external CSS styles", "बाह्य CSS शैलियों को पुनः लोड करें"}, + {"Note: any action done here are not persistent and not changes your config files.", "टिप्पणी: यहाँ किए गए कोई भी क्रियाएँ स्थायी नहीं हैं और आपके विन्यास संचिका में कोई परिवर्तन नहीं करतीं।"}, + {"Logging level", "लॉगिंग स्तर"}, + {"Transit tunnels limit", "संचरण सुरंगों की सीमा"}, + {"Change", "बदलना"}, + {"Change language", "भाषा बदलें"}, + {"no transit tunnels currently built", "संचरण सुरंगों का निर्माण नहीं हुआ है"}, + {"SAM disabled", "SAM निष्क्रिय है"}, + {"no sessions currently running", "वर्तमान में कोई सत्र सक्रिय नहीं है"}, + {"SAM session not found", "SAM सत्र नहीं मिला"}, + {"SAM Session", "SAM सत्र"}, + {"Server Tunnels", "सर्वर सुरंग"}, + {"Client Forwards", "क्लाइंट फॉरवर्ड्स"}, + {"Server Forwards", "सर्वर फॉरवर्ड्स"}, + {"Unknown page", "अज्ञात पृष्ठ"}, + {"Invalid token", "अमान्य टोकन"}, + {"SUCCESS", "सफलता"}, + {"Stream closed", "प्रवाह समाप्त हो गया है"}, + {"Stream not found or already was closed", "प्रवाह प्राप्त नहीं हुआ अथवा इसका पूर्व में ही समापन हो चुका है"}, + {"Destination not found", "गंतव्य नहीं मिला"}, + {"StreamID can't be null", "प्रवाह ID शून्य नहीं हो सकता है"}, + {"Return to destination page", "गंतव्य पृष्ठ पर पुनः वापस जाएँ"}, + {"You will be redirected in %d seconds", "आपको %d सेकंड में पुनर्निर्देशित किया जाएगा"}, + {"LeaseSet expiration time updated", "पट्ट समुच्चय की अवसान समय को अद्यतित किया गया है"}, + {"LeaseSet is not found or already expired", "पट्ट समुच्चय प्राप्त नहीं हुआ या इसका पूर्वमेव अवसान हो चुका है"}, + {"Transit tunnels count must not exceed %d", "संचरण सुरंगों की संख्या %d से अधिक नहीं होनी चाहिए"}, + {"Back to commands list", "आदेश सूची पर पुनः लौटें"}, + {"Register at reg.i2p", "reg.i2p पर पंजीकरण करें"}, + {"Description", "विवरण"}, + {"A bit information about service on domain", "डोमेन पर सेवा से संबंधित थोड़ी जानकारी"}, + {"Submit", "प्रस्तुत करें"}, + {"Domain can't end with .b32.i2p", "डोमेन का अंत .b32.i2p से नहीं हो सकता"}, + {"Domain must end with .i2p", "डोमेन का अंत .i2p से होना आवश्यक है"}, + {"Unknown command", "अज्ञात आदेश"}, + {"Command accepted", "आदेश स्वीकार किया गया"}, + {"Proxy error", "प्रॉक्सी त्रुटि"}, + {"Proxy info", "प्रॉक्सी जानकारी"}, + {"Proxy error: Host not found", "प्रॉक्सी त्रुटि: होस्ट नहीं मिला"}, + {"Remote host not found in router's addressbook", "राउटर की पता पुस्तक में दूरस्थ होस्ट नहीं मिला"}, + {"You may try to find this host on jump services below", "आप नीचे दिए गए जंप सेवाओं में इस होस्ट को खोजने की कोशिश कर सकते हैं"}, + {"Invalid request", "अमान्य अनुरोध"}, + {"Proxy unable to parse your request", "प्रॉक्सी आपके अनुरोध को विश्लेषित करने में असमर्थ है"}, + {"Addresshelper is not supported", "Addresshelper समर्थित नहीं है"}, + {"Host %s is already in router's addressbook. Be careful: source of this URL may be harmful! Click here to update record: Continue.", "होस्ट %s पहले से ही राउटर की पता-पुस्तिका में उपस्थित हैसावधान रहें: इस URL का स्रोत हानिकारक हो सकता है! अभिलेख को अद्यतन करने हेतु यहाँ क्लिक करें: जारी रखें।"}, + {"Addresshelper forced update rejected", "Addresshelper का जबरन अद्यतन अस्वीकृत किया गया"}, + {"To add host %s in router's addressbook, click here: Continue.", "राउटर की पता-पुस्तिका में होस्ट %s को जोड़ने हेतु, कृपया यहाँ क्लिक करें: जारी रखें।"}, + {"Addresshelper request", "Addresshelper अनुरोध"}, + {"Host %s added to router's addressbook from helper. Click here to proceed: Continue.", "सहायक से होस्ट %s राउटर की पता-पुस्तिका में जोड़ दिया गया है। आगे बढ़ने हेतु यहाँ क्लिक करें: जारी रखें।"}, + {"Addresshelper adding", "Addresshelper जोड़ना"}, + {"Host %s is already in router's addressbook. Click here to update record: Continue.", "होस्ट %s पहले से ही राउटर की पता-पुस्तिका में उपस्थित है। अभिलेख को अद्यतन करने हेतु यहाँ क्लिक करें: जारी रखें।"}, + {"Addresshelper update", "Addresshelper अद्यतन करना"}, + {"Invalid request URI", "अमान्य अनुरोध URI"}, + {"Can't detect destination host from request", "अनुरोध से गंतव्य होस्ट का पता नहीं लगा सकते"}, + {"Outproxy failure", "आउटप्रॉक्सी विफलता"}, + {"Bad outproxy settings", "गलत आउटप्रॉक्सी सेटिंग्स"}, + {"Host %s is not inside I2P network, but outproxy is not enabled", "होस्ट %s I2P नेटवर्क के भीतर नहीं है, लेकिन आउटप्रॉक्सी सक्षम नहीं है"}, + {"Unknown outproxy URL", "अज्ञात आउटप्रॉक्सी URL"}, + {"Cannot resolve upstream proxy", "ऊर्ध्वधारा प्रॉक्सी का समाधान नहीं किया जा सका"}, + {"Hostname is too long", "होस्टनाम अत्यधिक लंबा है"}, + {"Cannot connect to upstream SOCKS proxy", "उर्ध्वधारा SOCKS प्रॉक्सी से संपर्क स्थापित नहीं हो पा रहा है"}, + {"Cannot negotiate with SOCKS proxy", "SOCKS प्रॉक्सी के साथ समन्वयन स्थापित नहीं किया जा सका"}, + {"CONNECT error", "संपर्क त्रुटि"}, + {"Failed to connect", "संपर्क स्थापित करने में विफल"}, + {"SOCKS proxy error", "SOCKS प्रॉक्सी त्रुटि"}, + {"Failed to send request to upstream", "ऊर्ध्ववाहिनी को अनुरोध प्रेषित करने में विफलता हुई"}, + {"No reply from SOCKS proxy", "SOCKS प्रॉक्सी से कोई प्रत्युत्तर प्राप्त नहीं हुआ"}, + {"Cannot connect", "संपर्क नहीं हो पा रहा है"}, + {"HTTP out proxy not implemented", "HTTP आउट प्रॉक्सी कार्यान्वित नहीं किया गया है"}, + {"Cannot connect to upstream HTTP proxy", "उर्ध्वधारा HTTP प्रॉक्सी से संपर्क स्थापित नहीं हो पा रहा है"}, + {"Host is down", "होस्ट अनुपलब्ध है"}, + {"Can't create connection to requested host, it may be down. Please try again later.", "अनुरोधित होस्ट से संपर्क स्थापित नहीं किया जा सका। संभवतः वह सक्रिय नहीं है। कृपया बाद में पुनः प्रयास करें।"}, + {"", ""}, + }; + + static std::map> plurals + { + {"%d days", {"%d दिन", "%d दिन"}}, + {"%d hours", {"%d घंटा", "%dघंटे"}}, + {"%d minutes", {"%d मिनट", "%d मिनट"}}, + {"%d seconds", {"%d सेकंड", "%d सेकंड"}}, + {"", {"", "", ""}}, + }; + + std::shared_ptr GetLocale() + { + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); + } + +} // language +} // i18n +} // i2p diff --git a/i18n/I18N.h b/i18n/I18N.h index 8ed77a6b..00398f78 100644 --- a/i18n/I18N.h +++ b/i18n/I18N.h @@ -19,16 +19,17 @@ namespace i2p { namespace i18n { - typedef std::map LocaleStrings; + typedef std::map LocaleStrings; class Locale { public: Locale ( const std::string& language, + const bool& rtl, const LocaleStrings& strings, const std::map>& plurals, std::function formula - ): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { }; + ): m_Language (language), m_RTL (rtl), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { }; // Get activated language name for webconsole std::string GetLanguage() const @@ -36,6 +37,11 @@ namespace i18n return m_Language; } + bool GetRTL() const + { + return m_RTL; + } + std::string_view GetString (std::string_view arg) const { const auto it = m_Strings.find(arg); @@ -65,6 +71,7 @@ namespace i18n private: const std::string m_Language; + const bool m_RTL; const LocaleStrings m_Strings; const std::map> m_Plurals; std::function m_Formula; diff --git a/i18n/I18N_langs.h b/i18n/I18N_langs.h index 6426e2ce..b3d09af8 100644 --- a/i18n/I18N_langs.h +++ b/i18n/I18N_langs.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2021-2023, The PurpleI2P Project +* Copyright (c) 2021-2025, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -30,6 +30,8 @@ namespace i18n namespace english { std::shared_ptr GetLocale (); } namespace french { std::shared_ptr GetLocale (); } namespace german { std::shared_ptr GetLocale (); } + namespace hebrew { std::shared_ptr GetLocale (); } + namespace hindi { std::shared_ptr GetLocale (); } namespace italian { std::shared_ptr GetLocale (); } namespace polish { std::shared_ptr GetLocale (); } namespace portuguese { std::shared_ptr GetLocale (); } @@ -53,6 +55,8 @@ namespace i18n { "english", {"English", "en", i2p::i18n::english::GetLocale} }, { "french", {"Français", "fr", i2p::i18n::french::GetLocale} }, { "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} }, + { "hebrew", {"עִבְרִית‎", "he", i2p::i18n::hebrew::GetLocale} }, + { "hindi", {"हिन्दी", "hi", i2p::i18n::hindi::GetLocale} }, { "italian", {"Italiano", "it", i2p::i18n::italian::GetLocale} }, { "polish", {"Polski", "pl", i2p::i18n::polish::GetLocale} }, { "portuguese", {"Português", "pt", i2p::i18n::portuguese::GetLocale} }, diff --git a/i18n/Italian.cpp b/i18n/Italian.cpp index 0ae26f21..339654ba 100644 --- a/i18n/Italian.cpp +++ b/i18n/Italian.cpp @@ -29,6 +29,9 @@ namespace italian // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace italian // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Polish.cpp b/i18n/Polish.cpp index 0e8df096..97422e45 100644 --- a/i18n/Polish.cpp +++ b/i18n/Polish.cpp @@ -29,6 +29,9 @@ namespace polish // language namespace return (n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2); } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace polish // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Portuguese.cpp b/i18n/Portuguese.cpp index 26204dc3..970a7b8f 100644 --- a/i18n/Portuguese.cpp +++ b/i18n/Portuguese.cpp @@ -29,6 +29,9 @@ namespace portuguese // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace portuguese // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Russian.cpp b/i18n/Russian.cpp index 235cc0ae..e5bcb0b0 100644 --- a/i18n/Russian.cpp +++ b/i18n/Russian.cpp @@ -29,6 +29,9 @@ namespace russian // language namespace return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f КиБ"}, @@ -215,7 +218,7 @@ namespace russian // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Spanish.cpp b/i18n/Spanish.cpp index 0e657fb4..5b51ce4d 100644 --- a/i18n/Spanish.cpp +++ b/i18n/Spanish.cpp @@ -29,6 +29,9 @@ namespace spanish // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -196,7 +199,7 @@ namespace spanish // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Swedish.cpp b/i18n/Swedish.cpp index df13d22f..1dcb7e61 100644 --- a/i18n/Swedish.cpp +++ b/i18n/Swedish.cpp @@ -29,6 +29,9 @@ namespace swedish // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -211,7 +214,7 @@ namespace swedish // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Turkish.cpp b/i18n/Turkish.cpp index 9946b336..139b004e 100644 --- a/i18n/Turkish.cpp +++ b/i18n/Turkish.cpp @@ -29,6 +29,9 @@ namespace turkish // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -106,7 +109,7 @@ namespace turkish // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Turkmen.cpp b/i18n/Turkmen.cpp index 7efb8891..8cdcae52 100644 --- a/i18n/Turkmen.cpp +++ b/i18n/Turkmen.cpp @@ -29,6 +29,9 @@ namespace turkmen // language namespace return n != 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -196,7 +199,7 @@ namespace turkmen // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Ukrainian.cpp b/i18n/Ukrainian.cpp index c1b6c772..3c3c44a4 100644 --- a/i18n/Ukrainian.cpp +++ b/i18n/Ukrainian.cpp @@ -29,6 +29,9 @@ namespace ukrainian // language namespace return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f КіБ"}, @@ -215,7 +218,7 @@ namespace ukrainian // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language diff --git a/i18n/Uzbek.cpp b/i18n/Uzbek.cpp index 8e870772..681a8e19 100644 --- a/i18n/Uzbek.cpp +++ b/i18n/Uzbek.cpp @@ -29,6 +29,9 @@ namespace uzbek // language namespace return n > 1 ? 1 : 0; } + // Right to Left language? + static bool rtl = false; + static const LocaleStrings strings { {"%.2f KiB", "%.2f KiB"}, @@ -215,7 +218,7 @@ namespace uzbek // language namespace std::shared_ptr GetLocale() { - return std::make_shared(language, strings, plurals, [] (int n)->int { return plural(n); }); + return std::make_shared(language, rtl, strings, plurals, [] (int n)->int { return plural(n); }); } } // language