mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-11-13 15:57:22 +01:00
i18n: add Arabic (ar-SA) UI locale with RTL support
Add Modern Standard Arabic (ar-SA) as a selectable UI language alongside
the existing zh-CN, en-US and ru-RU locales.
- web/static/i18n/ar-SA.json: new Arabic locale (4272 leaf strings,
full key/placeholder parity with en-US). The `c2` and `webshell`
sections are intentionally omitted and fall back to English via the
i18next fallback chain (ar-SA -> en-US -> zh-CN).
- web/static/js/i18n.js: register ar-SA, detect `ar*` navigator language,
preload en-US as fallback, set document dir="rtl" for Arabic, and add
the ar-SA language label handling.
- web/static/i18n/{zh-CN,en-US,ru-RU}.json: add the `lang.arSA` label.
- web/templates/{index,api-docs}.html: add the العربية option to the
language dropdown.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
5affb4df1b
commit
caa7700345
7 files changed
+4624
-5
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -2,7 +2,8 @@
|
||||
"lang": {
|
||||
"zhCN": "中文",
|
||||
"enUS": "English",
|
||||
"ruRU": "Русский"
|
||||
"ruRU": "Русский",
|
||||
"arSA": "العربية"
|
||||
},
|
||||
"mobile": {
|
||||
"openNav": "Open navigation menu",
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"lang": {
|
||||
"zhCN": "中文",
|
||||
"enUS": "English",
|
||||
"ruRU": "Русский"
|
||||
"ruRU": "Русский",
|
||||
"arSA": "العربية"
|
||||
},
|
||||
"mobile": {
|
||||
"openNav": "Открыть меню навигации",
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
"lang": {
|
||||
"zhCN": "中文",
|
||||
"enUS": "English",
|
||||
"ruRU": "Русский"
|
||||
"ruRU": "Русский",
|
||||
"arSA": "العربية"
|
||||
},
|
||||
"mobile": {
|
||||
"openNav": "打开导航菜单",
|
||||
|
||||
+24
-2
@@ -29,12 +29,27 @@
|
||||
if (navLang.startsWith('ru')) {
|
||||
return 'ru-RU';
|
||||
}
|
||||
if (navLang.startsWith('ar')) {
|
||||
return 'ar-SA';
|
||||
}
|
||||
if (navLang.startsWith('en')) {
|
||||
return 'en-US';
|
||||
}
|
||||
return DEFAULT_LANG;
|
||||
}
|
||||
|
||||
// 根据语言设置文档方向(阿拉伯语为从右到左 RTL)
|
||||
function applyDirection(lang) {
|
||||
try {
|
||||
if (document && document.documentElement) {
|
||||
var l = String(lang || DEFAULT_LANG).toLowerCase();
|
||||
document.documentElement.dir = l.indexOf('ar') === 0 ? 'rtl' : 'ltr';
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
async function loadLanguageResources(lang) {
|
||||
if (loadedLangs[lang]) {
|
||||
return;
|
||||
@@ -114,6 +129,9 @@
|
||||
// ignore
|
||||
}
|
||||
|
||||
// 更新文档方向(RTL/LTR)
|
||||
applyDirection(i18next.language || DEFAULT_LANG);
|
||||
|
||||
try {
|
||||
if (typeof window.syncHitlAuditBackendUI === 'function') {
|
||||
window.syncHitlAuditBackendUI();
|
||||
@@ -129,6 +147,8 @@
|
||||
label.textContent = i18next.t('lang.zhCN');
|
||||
} else if (lang.indexOf('ru') === 0) {
|
||||
label.textContent = i18next.t('lang.ruRU');
|
||||
} else if (lang.indexOf('ar') === 0) {
|
||||
label.textContent = i18next.t('lang.arSA');
|
||||
} else {
|
||||
label.textContent = i18next.t('lang.enUS');
|
||||
}
|
||||
@@ -159,7 +179,7 @@
|
||||
const current = i18next.language || DEFAULT_LANG;
|
||||
if (lang === current) return;
|
||||
await loadLanguageResources(lang);
|
||||
if (lang === 'ru-RU') {
|
||||
if (lang === 'ru-RU' || lang === 'ar-SA') {
|
||||
await loadLanguageResources('en-US');
|
||||
}
|
||||
await i18next.changeLanguage(lang);
|
||||
@@ -193,6 +213,7 @@
|
||||
lng: initialLang,
|
||||
fallbackLng: {
|
||||
'ru-RU': ['en-US', 'zh-CN'],
|
||||
'ar-SA': ['en-US', 'zh-CN'],
|
||||
'default': [DEFAULT_LANG]
|
||||
},
|
||||
debug: false,
|
||||
@@ -200,7 +221,7 @@
|
||||
});
|
||||
|
||||
await loadLanguageResources(initialLang);
|
||||
if (initialLang === 'ru-RU') {
|
||||
if (initialLang === 'ru-RU' || initialLang === 'ar-SA') {
|
||||
await loadLanguageResources('en-US');
|
||||
}
|
||||
applyTranslations(document);
|
||||
@@ -221,6 +242,7 @@
|
||||
const lang = String((window.__locale || (typeof i18next !== 'undefined' && i18next.language) || '')).toLowerCase();
|
||||
if (lang.indexOf('zh') === 0) return 'zh-CN';
|
||||
if (lang.indexOf('ru') === 0) return 'ru-RU';
|
||||
if (lang.indexOf('ar') === 0) return 'ar-SA';
|
||||
return 'en-US';
|
||||
};
|
||||
window.changeLanguage = changeLanguage;
|
||||
|
||||
@@ -989,6 +989,7 @@
|
||||
<div class="lang-option" data-lang="zh-CN" onclick="typeof onLanguageSelect === 'function' && onLanguageSelect('zh-CN')">中文</div>
|
||||
<div class="lang-option" data-lang="en-US" onclick="typeof onLanguageSelect === 'function' && onLanguageSelect('en-US')">English</div>
|
||||
<div class="lang-option" data-lang="ru-RU" onclick="typeof onLanguageSelect === 'function' && onLanguageSelect('ru-RU')">Русский</div>
|
||||
<div class="lang-option" data-lang="ar-SA" onclick="typeof onLanguageSelect === 'function' && onLanguageSelect('ar-SA')">العربية</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
<div class="lang-option" data-lang="zh-CN" onclick="onLanguageSelect('zh-CN')">中文</div>
|
||||
<div class="lang-option" data-lang="en-US" onclick="onLanguageSelect('en-US')">English</div>
|
||||
<div class="lang-option" data-lang="ru-RU" onclick="onLanguageSelect('ru-RU')">Русский</div>
|
||||
<div class="lang-option" data-lang="ar-SA" onclick="onLanguageSelect('ar-SA')">العربية</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="notification-menu-container">
|
||||
|
||||
Reference in new issue
Block a user