using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public enum UILanguage { Chinese, English, French, Russian } public class LocalizationManager : MonoBehaviour { private class TextState { public string source; public string localized; public object[] formatArgs; } private class DropdownState { public List sources = new List(); public List localized = new List(); } public const string PreferenceKey = "UI.Language"; private const string FontResourcePath = "Localization/NotoSansCJKsc-Regular"; private static LocalizationManager instance; private readonly Dictionary textStates = new Dictionary(); private readonly Dictionary dropdownStates = new Dictionary(); private readonly Dictionary table = new Dictionary { { "装备抢修模拟训练系统", new[] { "装备抢修模拟训练系统", "Equipment Emergency Repair Simulation", "Simulation de réparation d'urgence", "Симулятор аварийного ремонта" } }, { "登陆界面", new[] { "登陆界面", "Login", "Connexion", "Вход" } }, { "登录", new[] { "登录", "Login", "Connexion", "Войти" } }, { "用户:", new[] { "用户:", "User:", "Utilisateur :", "Пользователь:" } }, { "密码:", new[] { "密码:", "Password:", "Mot de passe :", "Пароль:" } }, { "用户名", new[] { "用户名", "Username", "Nom d'utilisateur", "Имя пользователя" } }, { "密码", new[] { "密码", "Password", "Mot de passe", "Пароль" } }, { "管理员", new[] { "管理员", "Administrator", "Administrateur", "Администратор" } }, { "超级用户", new[] { "超级用户", "Super User", "Super utilisateur", "Суперпользователь" } }, { "教师", new[] { "教师", "Instructor", "Instructeur", "Преподаватель" } }, { "学员", new[] { "学员", "Student", "Stagiaire", "Обучаемый" } }, { "确定", new[] { "确定", "Confirm", "Confirmer", "Подтвердить" } }, { "取消", new[] { "取消", "Cancel", "Annuler", "Отмена" } }, { "关闭", new[] { "关闭", "Close", "Fermer", "Закрыть" } }, { "查询", new[] { "查询", "Search", "Rechercher", "Поиск" } }, { "添加", new[] { "添加", "Add", "Ajouter", "Добавить" } }, { "删除", new[] { "删除", "Delete", "Supprimer", "Удалить" } }, { "修改", new[] { "修改", "Edit", "Modifier", "Изменить" } }, { "保存", new[] { "保存", "Save", "Enregistrer", "Сохранить" } }, { "返回", new[] { "返回", "Back", "Retour", "Назад" } }, { "退出登录", new[] { "退出登录", "Sign Out", "Se déconnecter", "Выйти" } }, { "用户管理", new[] { "用户管理", "User Management", "Gestion des utilisateurs", "Управление пользователями" } }, { "数据管理", new[] { "数据管理", "Data Management", "Gestion des données", "Управление данными" } }, { "历史记录", new[] { "历史记录", "History", "Historique", "История" } }, { "开始训练", new[] { "开始训练", "Start Training", "Démarrer l'entraînement", "Начать обучение" } }, { "历史查询", new[] { "历史查询", "History Search", "Recherche d'historique", "Поиск в истории" } }, { "下发科目", new[] { "下发科目", "Send Subject", "Envoyer le sujet", "Отправить задание" } }, { "结束任务", new[] { "结束任务", "End Task", "Terminer la tâche", "Завершить задание" } }, { "选择模式", new[] { "选择模式", "Select Mode", "Sélectionner le mode", "Выбрать режим" } }, { "训练模式", new[] { "训练模式", "Training Mode", "Mode entraînement", "Режим тренировки" } }, { "考核模式", new[] { "考核模式", "Assessment Mode", "Mode évaluation", "Режим оценки" } }, { "选择科目", new[] { "选择科目", "Select Subject", "Sélectionner le sujet", "Выбрать задание" } }, { "选择天气", new[] { "选择天气", "Select Weather", "Sélectionner la météo", "Выбрать погоду" } }, { "选择案例", new[] { "选择案例", "Select Case", "Sélectionner le cas", "Выбрать случай" } }, { "山地", new[] { "山地", "Mountain", "Montagne", "Горы" } }, { "平原", new[] { "平原", "Plain", "Plaine", "Равнина" } }, { "城市", new[] { "城市", "City", "Ville", "Город" } }, { "城镇", new[] { "城镇", "Town", "Ville", "Город" } }, { "晴", new[] { "晴", "Sunny", "Ensoleillé", "Ясно" } }, { "雨", new[] { "雨", "Rain", "Pluie", "Дождь" } }, { "雪", new[] { "雪", "Snow", "Neige", "Снег" } }, { "编队行军", new[] { "编队行军", "Convoy March", "Marche en convoi", "Марш колонной" } }, { "修理所展开", new[] { "修理所展开", "Repair Site Deployment", "Déploiement du site de réparation", "Развёртывание ремонтного пункта" } }, { "装备抢修", new[] { "装备抢修", "Equipment Emergency Repair", "Réparation d'urgence", "Аварийный ремонт техники" } }, { "装备维修", new[] { "装备维修", "Equipment Maintenance", "Maintenance des équipements", "Техническое обслуживание" } }, { "训练", new[] { "训练", "Training", "Entraînement", "Тренировка" } }, { "考核", new[] { "考核", "Assessment", "Évaluation", "Оценка" } }, { "未下发科目", new[] { "未下发科目", "No Subject Assigned", "Aucun sujet attribué", "Задание не назначено" } }, { "训练中", new[] { "训练中", "Training", "Entraînement", "Тренировка" } }, { "考核中", new[] { "考核中", "Assessment", "Évaluation", "Оценка" } }, { "二维模式", new[] { "二维模式", "2D Mode", "Mode 2D", "2D-режим" } }, { "三维模式", new[] { "三维模式", "3D Mode", "Mode 3D", "3D-режим" } }, { "查看详情", new[] { "查看详情", "View Details", "Voir les détails", "Просмотреть детали" } }, { "结束训练", new[] { "结束训练", "End Training", "Terminer l'entraînement", "Завершить обучение" } }, { "任务简介:", new[] { "任务简介:", "Task Description:", "Description de la tâche :", "Описание задания:" } }, { "想定介绍:", new[] { "想定介绍:", "Scenario Description:", "Description du scénario :", "Описание сценария:" } }, { "当前科目:", new[] { "当前科目:", "Current Subject:", "Sujet actuel :", "Текущее задание:" } }, { "当前地形:", new[] { "当前地形:", "Current Terrain:", "Terrain actuel :", "Текущая местность:" } }, { "等待教员选择科目...", new[] { "等待教员选择科目...", "Waiting for instructor to select a subject...", "En attente de la sélection du sujet par l'instructeur...", "Ожидание выбора задания преподавателем..." } }, { "资源加载中,请稍后...", new[] { "资源加载中,请稍后...", "Loading resources, please wait...", "Chargement des ressources, veuillez patienter...", "Загрузка ресурсов, пожалуйста, подождите..." } }, { "服务器断开链接!", new[] { "服务器断开链接!", "Server connection lost!", "Connexion au serveur perdue !", "Соединение с сервером потеряно!" } }, { "未输入有效的用户名/密码!", new[] { "未输入有效的用户名/密码!", "Enter a valid username and password!", "Saisissez un nom d'utilisateur et un mot de passe valides !", "Введите корректные имя пользователя и пароль!" } }, { "用户名/密码不正确!", new[] { "用户名/密码不正确!", "Incorrect username or password!", "Nom d'utilisateur ou mot de passe incorrect !", "Неверное имя пользователя или пароль!" } }, { "账户名/密码错误!", new[] { "账户名/密码错误!", "Incorrect account name or password!", "Nom de compte ou mot de passe incorrect !", "Неверное имя учётной записи или пароль!" } }, { "该用户已经登录!", new[] { "该用户已经登录!", "This user is already logged in!", "Cet utilisateur est déjà connecté !", "Этот пользователь уже вошёл в систему!" } }, { "新增学员", new[] { "新增学员", "Add Student", "Ajouter un stagiaire", "Добавить обучаемого" } }, { "新增教员", new[] { "新增教员", "Add Instructor", "Ajouter un instructeur", "Добавить инструктора" } }, { "修改学员用户", new[] { "修改学员用户", "Edit Student", "Modifier le stagiaire", "Изменить обучаемого" } }, { "修改教员用户", new[] { "修改教员用户", "Edit Instructor", "Modifier l'instructeur", "Изменить инструктора" } }, { "用户名/密码不能为空!", new[] { "用户名/密码不能为空!", "Username/password cannot be empty!", "Le nom d'utilisateur/mot de passe ne peut pas être vide !", "Имя пользователя/пароль не могут быть пустыми!" } }, { "两次输入密码不一致!", new[] { "两次输入密码不一致!", "The passwords do not match!", "Les mots de passe ne correspondent pas !", "Пароли не совпадают!" } }, { "添加成功!", new[] { "添加成功!", "Added successfully!", "Ajout réussi !", "Успешно добавлено!" } }, { "添加失败,该用户已存在!", new[] { "添加失败,该用户已存在!", "Add failed: user already exists!", "Échec de l'ajout : l'utilisateur existe déjà !", "Добавление не выполнено: пользователь уже существует!" } }, { "新密码不能为空!", new[] { "新密码不能为空!", "New password cannot be empty!", "Le nouveau mot de passe ne peut pas être vide !", "Новый пароль не может быть пустым!" } }, { "密码修改成功!", new[] { "密码修改成功!", "Password changed successfully!", "Mot de passe modifié avec succès !", "Пароль успешно изменён!" } }, { "保存成功!", new[] { "保存成功!", "Saved successfully!", "Enregistré avec succès !", "Успешно сохранено!" } }, { "保存失败,数据库异常!", new[] { "保存失败,数据库异常!", "Save failed: database error!", "Échec de l'enregistrement : erreur de base de données !", "Сохранение не выполнено: ошибка базы данных!" } }, { "未查询到符合条件的记录!", new[] { "未查询到符合条件的记录!", "No matching records found!", "Aucun enregistrement correspondant trouvé !", "Подходящие записи не найдены!" } }, { "未评价时无需发送!", new[] { "未评价时无需发送!", "No evaluation to send!", "Aucune évaluation à envoyer !", "Нет оценки для отправки!" } }, { "学员已关闭成绩显示面板", new[] { "学员已关闭成绩显示面板", "The student closed the results panel.", "Le stagiaire a fermé le panneau des résultats.", "Обучаемый закрыл панель результатов." } }, { "请选择选项后确认", new[] { "请选择选项后确认", "Select an option before confirming.", "Sélectionnez une option avant de confirmer.", "Выберите вариант перед подтверждением." } }, { "是否不再等待教员评价,并返回初始场景?", new[] { "是否不再等待教员评价,并返回初始场景?", "Stop waiting for instructor evaluation and return to the initial scene?", "Cesser d'attendre l'évaluation de l'instructeur et revenir à la scène initiale ?", "Прекратить ожидание оценки преподавателя и вернуться к начальной сцене?" } }, // Fixed labels, prompts, and dropdown options used by teacher and student UI prefabs. { "结束导调", new[] { "结束导调", "End Direction", "Terminer la direction", "Завершить руководство" } }, { "等待界面初始化数据...", new[] { "等待界面初始化数据...", "Waiting for interface initialization data...", "En attente des données d'initialisation de l'interface...", "Ожидание данных инициализации интерфейса..." } }, { "若长时间无法获取初始化数据,请结束导调后重试!", new[] { "若长时间无法获取初始化数据,请结束导调后重试!", "If initialization data is unavailable for a long time, end direction and try again!", "Si les données d'initialisation restent indisponibles, terminez la direction et réessayez !", "Если данные инициализации долго недоступны, завершите руководство и повторите попытку!" } }, { "首选线路", new[] { "首选线路", "Preferred Route", "Itinéraire préféré", "Предпочтительный маршрут" } }, { "备选线路", new[] { "备选线路", "Alternate Route", "Itinéraire alternatif", "Альтернативный маршрут" } }, { "首选路径", new[] { "首选路径", "Preferred Path", "Chemin préféré", "Предпочтительный путь" } }, { "备选路径", new[] { "备选路径", "Alternate Path", "Chemin alternatif", "Альтернативный путь" } }, { "工具清单", new[] { "工具清单", "Tool List", "Liste des outils", "Список инструментов" } }, { "姓名和学号不能为空!", new[] { "姓名和学号不能为空!", "Name and student ID cannot be empty!", "Le nom et le numéro d'étudiant ne peuvent pas être vides !", "Имя и номер обучаемого не могут быть пустыми!" } }, { "名 称:", new[] { "名 称:", "Name:", "Nom :", "Название:" } }, { "类 型:", new[] { "类 型:", "Type:", "Type :", "Тип:" } }, { "装备", new[] { "装备", "Equipment", "Équipement", "Оборудование" } }, { "工具", new[] { "工具", "Tools", "Outils", "Инструменты" } }, { "地形", new[] { "地形", "Terrain", "Terrain", "Местность" } }, { "天候", new[] { "天候", "Weather", "Météo", "Погода" } }, { "导入模型", new[] { "导入模型", "Import Model", "Importer un modèle", "Импортировать модель" } }, { "选择文件", new[] { "选择文件", "Select File", "Sélectionner un fichier", "Выбрать файл" } }, { "文件路径:", new[] { "文件路径:", "File Path:", "Chemin du fichier :", "Путь к файлу:" } }, { "装备清单", new[] { "装备清单", "Equipment List", "Liste des équipements", "Список оборудования" } }, { "新增模型", new[] { "新增模型", "Add Model", "Ajouter un modèle", "Добавить модель" } }, { "地形库", new[] { "地形库", "Terrain Library", "Bibliothèque de terrains", "Библиотека местности" } }, { "天候库", new[] { "天候库", "Weather Library", "Bibliothèque météo", "Библиотека погоды" } }, { "操作详情:", new[] { "操作详情:", "Operation Details:", "Détails des opérations :", "Сведения об операциях:" } }, { "录屏文件路径:无", new[] { "录屏文件路径:无", "Recording File Path: None", "Chemin du fichier d'enregistrement : aucun", "Путь к файлу записи: нет" } }, { "播放录屏视频", new[] { "播放录屏视频", "Play Recording", "Lire l'enregistrement", "Воспроизвести запись" } }, { "用时:", new[] { "用时:", "Duration:", "Durée :", "Продолжительность:" } }, { "开始导调", new[] { "开始导调", "Start Direction", "Démarrer la direction", "Начать руководство" } }, { " 开始导调", new[] { " 开始导调", " Start Direction", " Démarrer la direction", " Начать руководство" } }, { "新建想定", new[] { "新建想定", "New Scenario", "Nouveau scénario", "Новый сценарий" } }, { "查询历史数据", new[] { "查询历史数据", "Query History", "Consulter l'historique", "Запросить историю" } }, { "科目下发成功!/请选择席位后下发科目!", new[] { "科目下发成功!/请选择席位后下发科目!", "Subject sent successfully! / Select seats before sending the subject!", "Sujet envoyé avec succès ! / Sélectionnez des postes avant d'envoyer le sujet !", "Задание успешно отправлено! / Выберите места перед отправкой задания!" } }, { "按下Ctrl可选择多个席位。", new[] { "按下Ctrl可选择多个席位。", "Hold Ctrl to select multiple seats.", "Maintenez Ctrl pour sélectionner plusieurs postes.", "Удерживайте Ctrl, чтобы выбрать несколько мест." } }, { "请选择将要结束的席位!", new[] { "请选择将要结束的席位!", "Select the seat to end!", "Sélectionnez le poste à terminer !", "Выберите место для завершения!" } }, { "想定文件信息", new[] { "想定文件信息", "Scenario File Information", "Informations du fichier scénario", "Сведения о файле сценария" } }, { "选择想定文件", new[] { "选择想定文件", "Select Scenario File", "Sélectionner un fichier scénario", "Выбрать файл сценария" } }, { "展开科目协同训练", new[] { "展开科目协同训练", "Conduct Subject Collaborative Training", "Mener l'entraînement collaboratif du sujet", "Провести совместную тренировку по заданию" } }, { "编辑想定", new[] { "编辑想定", "Edit Scenario", "Modifier le scénario", "Редактировать сценарий" } }, { "设为组长", new[] { "设为组长", "Set as Leader", "Définir comme chef", "Назначить руководителем" } }, { "创建编组", new[] { "创建编组", "Create Group", "Créer un groupe", "Создать группу" } }, { "设定天候", new[] { "设定天候", "Set Weather", "Définir la météo", "Установить погоду" } }, { "播放维修动画", new[] { "播放维修动画", "Play Repair Animation", "Lire l'animation de réparation", "Воспроизвести анимацию ремонта" } }, { "晴天", new[] { "晴天", "Sunny", "Ensoleillé", "Ясно" } }, { "雨天", new[] { "雨天", "Rainy", "Pluvieux", "Дождливо" } }, { "雪天", new[] { "雪天", "Snowy", "Neigeux", "Снежно" } }, { "维修案例1", new[] { "维修案例1", "Repair Case 1", "Cas de réparation 1", "Случай ремонта 1" } }, { "维修案例2", new[] { "维修案例2", "Repair Case 2", "Cas de réparation 2", "Случай ремонта 2" } }, { "加入编组", new[] { "加入编组", "Add to Group", "Ajouter au groupe", "Добавить в группу" } }, { "移出编组", new[] { "移出编组", "Remove from Group", "Retirer du groupe", "Удалить из группы" } }, { "新增用户", new[] { "新增用户", "Add User", "Ajouter un utilisateur", "Добавить пользователя" } }, { "操作", new[] { "操作", "Actions", "Actions", "Действия" } }, { "重复密码", new[] { "重复密码", "Repeat Password", "Répéter le mot de passe", "Повторите пароль" } }, { "第1页/共15页", new[] { "第1页/共15页", "Page 1 of 15", "Page 1 sur 15", "Страница 1 из 15" } }, { "学员用户名:", new[] { "学员用户名:", "Student Username:", "Nom d'utilisateur du stagiaire :", "Имя пользователя обучаемого:" } }, { "请输入姓名...", new[] { "请输入姓名...", "Enter name...", "Saisissez le nom...", "Введите имя..." } }, { "教员用户名:", new[] { "教员用户名:", "Instructor Username:", "Nom d'utilisateur de l'instructeur :", "Имя пользователя преподавателя:" } }, { "起始日期:", new[] { "起始日期:", "Start Date:", "Date de début :", "Дата начала:" } }, { "日期格式:xxxx-xx-xx", new[] { "日期格式:xxxx-xx-xx", "Date Format: xxxx-xx-xx", "Format de date : xxxx-xx-xx", "Формат даты: xxxx-xx-xx" } }, { "评价", new[] { "评价", "Evaluation", "Évaluation", "Оценка" } }, { "操作时间", new[] { "操作时间", "Operation Time", "Heure de l'opération", "Время операции" } }, { "用时", new[] { "用时", "Duration", "Durée", "Продолжительность" } }, { "学员:", new[] { "学员:", "Student:", "Stagiaire :", "Обучаемый:" } }, { "终止日期:", new[] { "终止日期:", "End Date:", "Date de fin :", "Дата окончания:" } }, { "模式", new[] { "模式", "Mode", "Mode", "Режим" } }, { "按时间查找", new[] { "按时间查找", "Search by Time", "Rechercher par heure", "Поиск по времени" } }, { "科目", new[] { "科目", "Subject", "Sujet", "Задание" } }, { "退出编辑", new[] { "退出编辑", "Exit Editing", "Quitter l'édition", "Выйти из редактирования" } }, { "人员库清单", new[] { "人员库清单", "Personnel Library", "Bibliothèque du personnel", "Библиотека персонала" } }, { "突发情况(拖拽到地图特定位置完成设置)", new[] { "突发情况(拖拽到地图特定位置完成设置)", "Incident (drag to a map location to set)", "Incident (faites glisser vers un emplacement de la carte pour définir)", "Инцидент (перетащите в нужное место на карте для настройки)" } }, { "存储想定", new[] { "存储想定", "Save Scenario", "Enregistrer le scénario", "Сохранить сценарий" } }, { "附属装备:", new[] { "附属装备:", "Attached Equipment:", "Équipement associé :", "Прикреплённое оборудование:" } }, { "附属人员:", new[] { "附属人员:", "Attached Personnel:", "Personnel associé :", "Прикреплённый персонал:" } }, { "移除装备", new[] { "移除装备", "Remove Equipment", "Retirer l'équipement", "Удалить оборудование" } }, { "结束侦察", new[] { "结束侦察", "End Reconnaissance", "Terminer la reconnaissance", "Завершить разведку" } }, { "场景加载中请稍后....", new[] { "场景加载中请稍后....", "Loading scene, please wait....", "Chargement de la scène, veuillez patienter....", "Загрузка сцены, пожалуйста, подождите...." } }, { "教员评语", new[] { "教员评语", "Instructor Comments", "Commentaires de l'instructeur", "Комментарии преподавателя" } }, { "教员评价:", new[] { "教员评价:", "Instructor Evaluation:", "Évaluation de l'instructeur :", "Оценка преподавателя:" } }, { "训练评估", new[] { "训练评估", "Training Evaluation", "Évaluation de l'entraînement", "Оценка тренировки" } }, { "优秀", new[] { "优秀", "Excellent", "Excellent", "Отлично" } }, { "良好", new[] { "良好", "Good", "Bien", "Хорошо" } }, { "一般", new[] { "一般", "Average", "Moyen", "Удовлетворительно" } }, { "较差", new[] { "较差", "Poor", "Faible", "Плохо" } }, { "本课目训练完毕,等待教员评分...", new[] { "本课目训练完毕,等待教员评分...", "This subject is complete; waiting for instructor scoring...", "Ce sujet est terminé ; en attente de la notation de l'instructeur...", "Задание завершено; ожидание оценки преподавателя..." } }, { "本科目训练完毕,等待教员评分...", new[] { "本科目训练完毕,等待教员评分...", "This subject is complete; waiting for instructor scoring...", "Ce sujet est terminé ; en attente de la notation de l'instructeur...", "Задание завершено; ожидание оценки преподавателя..." } }, { "{1}", new[] { "{1}", "{1}", "{1}", "{1}" } }, { "标记首车", new[] { "标记首车", "Mark Lead Vehicle", "Marquer le véhicule de tête", "Отметить головную машину" } }, { "指挥组", new[] { "指挥组", "Command Group", "Groupe de commandement", "Группа управления" } }, { "结束规划", new[] { "结束规划", "Finish Planning", "Terminer la planification", "Завершить планирование" } }, { "所属编组:", new[] { "所属编组:", "Assigned Group:", "Groupe assigné :", "Назначенная группа:" } }, { "平均车速:", new[] { "平均车速:", "Average Vehicle Speed:", "Vitesse moyenne des véhicules :", "Средняя скорость машин:" } }, { "前出保障组", new[] { "前出保障组", "Forward Support Group", "Groupe de soutien avancé", "Группа передового обеспечения" } }, { "殿后保障组", new[] { "殿后保障组", "Rear Support Group", "Groupe de soutien arrière", "Группа тылового обеспечения" } }, { "抢救抢修队", new[] { "抢救抢修队", "Rescue and Repair Team", "Équipe de sauvetage et réparation", "Аварийно-ремонтная команда" } }, { "主体编队", new[] { "主体编队", "Main Formation", "Formation principale", "Основная колонна" } }, { "标记尾车", new[] { "标记尾车", "Mark Rear Vehicle", "Marquer le véhicule de queue", "Отметить замыкающую машину" } }, { "查看地形", new[] { "查看地形", "View Terrain", "Voir le terrain", "Просмотреть местность" } }, { "编队完成", new[] { "编队完成", "Formation Complete", "Formation terminée", "Формирование завершено" } }, { "当前科目推演完毕,即将返回初始场景...", new[] { "当前科目推演完毕,即将返回初始场景...", "Current subject simulation complete; returning to the initial scene...", "Simulation du sujet actuel terminée ; retour à la scène initiale...", "Моделирование текущего задания завершено; возврат к начальной сцене..." } }, { "开始测距", new[] { "开始测距", "Start Measuring Distance", "Commencer la mesure de distance", "Начать измерение расстояния" } }, { "提示:厂区规划后,需点击完成按钮,否则无法继续。", new[] { "提示:厂区规划后,需点击完成按钮,否则无法继续。", "Tip: After planning the facility area, click Finish to continue.", "Conseil : après la planification de la zone, cliquez sur Terminer pour continuer.", "Подсказка: после планирования территории нажмите «Завершить», чтобы продолжить." } }, { "厂区规划完成", new[] { "厂区规划完成", "Facility Planning Complete", "Planification de la zone terminée", "Планирование территории завершено" } }, { "观察完毕,开始维修", new[] { "观察完毕,开始维修", "Observation Complete, Start Repair", "Observation terminée, commencer la réparation", "Наблюдение завершено, начать ремонт" } }, { "待规划维修步骤", new[] { "待规划维修步骤", "Repair Steps to Plan", "Étapes de réparation à planifier", "Шаги ремонта для планирования" } }, { "提交", new[] { "提交", "Submit", "Soumettre", "Отправить" } }, { "结束科目", new[] { "结束科目", "End Subject", "Terminer le sujet", "Завершить задание" } }, { "拟定维修策略", new[] { "拟定维修策略", "Develop Repair Strategy", "Élaborer une stratégie de réparation", "Разработать стратегию ремонта" } }, { "倒计时:30", new[] { "倒计时:30", "Countdown: 30", "Compte à rebours : 30", "Обратный отсчёт: 30" } }, { "行军过程中遇到敌方小股部队袭击,请选择处理方式:", new[] { "行军过程中遇到敌方小股部队袭击,请选择处理方式:", "A small enemy unit attacked during the march. Select a response:", "Une petite unité ennemie a attaqué pendant la marche. Sélectionnez une réponse :", "Во время марша атаковало небольшое подразделение противника. Выберите действие:" } }, { "发送失败提示", new[] { "发送失败提示", "Send Failure Notice", "Notification d'échec d'envoi", "Уведомление об ошибке отправки" } }, { "指定视频文件", new[] { "指定视频文件", "Select Video File", "Sélectionner un fichier vidéo", "Выбрать видеофайл" } }, { "系统评估扣分:", new[] { "系统评估扣分:", "System Evaluation Deduction:", "Déduction de l'évaluation système :", "Снижение баллов по системной оценке:" } }, { "下发评价", new[] { "下发评价", "Send Evaluation", "Envoyer l'évaluation", "Отправить оценку" } }, { "未评价", new[] { "未评价", "Not Evaluated", "Non évalué", "Не оценено" } }, { "存储数据", new[] { "存储数据", "Save Data", "Enregistrer les données", "Сохранить данные" } }, { "存储结果提示", new[] { "存储结果提示", "Save Result Notice", "Notification du résultat d'enregistrement", "Уведомление о результате сохранения" } }, { "系统评估指标及权重", new[] { "系统评估指标及权重", "System Evaluation Criteria and Weights", "Critères et pondérations de l'évaluation système", "Критерии и веса системной оценки" } }, { "教员点评:", new[] { "教员点评:", "Instructor Remarks:", "Remarques de l'instructeur :", "Замечания преподавателя:" } }, { "关联视频文件", new[] { "关联视频文件", "Linked Video File", "Fichier vidéo associé", "Связанный видеофайл" } }, { "发送提示", new[] { "发送提示", "Send Notice", "Notification d'envoi", "Уведомление об отправке" } }, { "存储提示", new[] { "存储提示", "Save Notice", "Notification d'enregistrement", "Уведомление о сохранении" } }, { "型号组成:", new[] { "型号组成:", "Model Composition:", "Composition du modèle :", "Состав модели:" } }, { "选择错误,应{0}", new[] { "选择错误,应{0}", "Incorrect choice; the correct answer is {0}", "Choix incorrect ; la bonne réponse est {0}", "Неверный выбор; правильный ответ: {0}" } }, { "当前科目为:{0}", new[] { "当前科目为:{0}", "Current subject: {0}", "Sujet actuel : {0}", "Текущее задание: {0}" } }, { "推演时间: {0}:{1}:{2}", new[] { "推演时间: {0}:{1}:{2}", "Simulation time: {0}:{1}:{2}", "Temps de simulation : {0}:{1}:{2}", "Время моделирования: {0}:{1}:{2}" } }, { "重新规划厂区位置", new[] { "重新规划厂区位置", "Replan Facility Area", "Replanifier la zone", "Перепланировать территорию" } }, { "移动中...", new[] { "移动中...", "Moving...", "Déplacement...", "Перемещение..." } }, { "展开车辆", new[] { "展开车辆", "Deploy Vehicle", "Déployer le véhicule", "Развернуть машину" } }, { "展开中...", new[] { "展开中...", "Deploying...", "Déploiement...", "Развёртывание..." } }, { "收起中...", new[] { "收起中...", "Stowing...", "Rangement...", "Сворачивание..." } }, { "收起车辆", new[] { "收起车辆", "Stow Vehicle", "Ranger le véhicule", "Свернуть машину" } }, { "未完成所有厂区的规划!", new[] { "未完成所有厂区的规划!", "All facility areas have not been planned!", "Toutes les zones ne sont pas planifiées !", "Спланированы не все территории!" } }, { "存在未规划的车辆{0}!", new[] { "存在未规划的车辆{0}!", "Vehicle {0} has not been planned!", "Le véhicule {0} n'est pas planifié !", "Машина {0} не спланирована!" } }, { "{0}地图加载失败,请检查资源文件后重试!", new[] { "{0}地图加载失败,请检查资源文件后重试!", "Failed to load the {0} map. Check the resource files and try again!", "Échec du chargement de la carte {0}. Vérifiez les fichiers de ressources et réessayez !", "Не удалось загрузить карту {0}. Проверьте файлы ресурсов и повторите попытку!" } }, { "未规划{0}线路", new[] { "未规划{0}线路", "{0} route has not been planned", "L'itinéraire {0} n'est pas planifié", "Маршрут {0} не спланирован" } }, { "未规划首选线路", new[] { "未规划首选线路", "Preferred route has not been planned", "L'itinéraire préféré n'est pas planifié", "Предпочтительный маршрут не спланирован" } }, { "未规划备选线路", new[] { "未规划备选线路", "Alternate route has not been planned", "L'itinéraire alternatif n'est pas planifié", "Альтернативный маршрут не спланирован" } }, { "装备/人员未完成编辑", new[] { "装备/人员未完成编辑", "Equipment/personnel editing is incomplete", "L'édition de l'équipement/du personnel est incomplète", "Редактирование оборудования/персонала не завершено" } }, { "未编辑主体编队", new[] { "未编辑主体编队", "Main formation has not been edited", "La formation principale n'est pas configurée", "Основная колонна не настроена" } }, { "未编辑前出保障组", new[] { "未编辑前出保障组", "Forward support group has not been edited", "Le groupe de soutien avancé n'est pas configuré", "Группа передового обеспечения не настроена" } }, { "未编辑抢救抢修队", new[] { "未编辑抢救抢修队", "Rescue and repair team has not been edited", "L'équipe de sauvetage et réparation n'est pas configurée", "Аварийно-ремонтная команда не настроена" } }, { "未编辑指挥组", new[] { "未编辑指挥组", "Command group has not been edited", "Le groupe de commandement n'est pas configuré", "Группа управления не настроена" } }, { "未编辑殿后保障组", new[] { "未编辑殿后保障组", "Rear support group has not been edited", "Le groupe de soutien arrière n'est pas configuré", "Группа тылового обеспечения не настроена" } }, { "未编辑前进保障队", new[] { "未编辑前进保障队", "Forward security team has not been edited", "L'équipe de sécurité avancée n'est pas configurée", "Передовая группа обеспечения не настроена" } }, { "编队中存在空车", new[] { "编队中存在空车", "The formation contains empty vehicles", "La formation contient des véhicules vides", "В колонне есть пустые машины" } }, { "未标记首/尾车辆", new[] { "未标记首/尾车辆", "Lead/rear vehicles have not been marked", "Les véhicules de tête/de queue ne sont pas marqués", "Головная/замыкающая машины не отмечены" } }, { "第{0}页/共{1}页", new[] { "第{0}页/共{1}页", "Page {0} of {1}", "Page {0} sur {1}", "Страница {0} из {1}" } }, { "转运耗时:{0}分:{1}秒", new[] { "转运耗时:{0}分:{1}秒", "Transfer time: {0} min {1} sec", "Temps de transfert : {0} min {1} s", "Время перевозки: {0} мин {1} с" } }, { "{0}分钟", new[] { "{0}分钟", "{0} minutes", "{0} minutes", "{0} мин." } }, { "x{0}", new[] { "x{0}", "x{0}", "x{0}", "x{0}" } }, { "当前登录学员:{0},训练中:{1},考核中:{2},等待中:{3}", new[] { "当前登录学员:{0},训练中:{1},考核中:{2},等待中:{3}", "Students online: {0}, training: {1}, assessment: {2}, waiting: {3}", "Stagiaires connectés : {0}, entraînement : {1}, évaluation : {2}, attente : {3}", "Обучаемых онлайн: {0}, тренировка: {1}, оценка: {2}, ожидание: {3}" } }, { "未选择待结束席位!", new[] { "未选择待结束席位!", "No seat selected to end!", "Aucun poste sélectionné à terminer !", "Не выбрано место для завершения!" } }, { "请选择单个席位进行导调!", new[] { "请选择单个席位进行导调!", "Select one seat for direction!", "Sélectionnez un seul poste pour le guidage !", "Выберите одно место для руководства!" } }, { "行军中的席位可进行导调!", new[] { "行军中的席位可进行导调!", "Only seats in march can be directed!", "Seuls les postes en marche peuvent être guidés !", "Руководство доступно только для мест в марше!" } }, { "请选择席位!", new[] { "请选择席位!", "Select a seat!", "Sélectionnez un poste !", "Выберите место!" } }, { "请选择训练模式!", new[] { "请选择训练模式!", "Select a training mode!", "Sélectionnez un mode d'entraînement !", "Выберите режим тренировки!" } }, { "请选择想定文件!", new[] { "请选择想定文件!", "Select a scenario file!", "Sélectionnez un fichier scénario !", "Выберите файл сценария!" } }, { "维修科目训练模式无需发送科目!", new[] { "维修科目训练模式无需发送科目!", "Maintenance training mode does not require sending a subject!", "Le mode d'entraînement de maintenance ne nécessite pas l'envoi d'un sujet !", "Режим тренировки по обслуживанию не требует отправки задания!" } }, { "请选择维修案例!", new[] { "请选择维修案例!", "Select a repair case!", "Sélectionnez un cas de réparation !", "Выберите случай ремонта!" } }, { "选择席位正在训练中,无法重复下发科目!", new[] { "选择席位正在训练中,无法重复下发科目!", "The selected seat is training; the subject cannot be sent again!", "Le poste sélectionné est en entraînement ; le sujet ne peut pas être envoyé à nouveau !", "Выбранное место проходит тренировку; задание нельзя отправить повторно!" } }, { "编队行军科目不支持协同训练!", new[] { "编队行军科目不支持协同训练!", "Convoy March does not support collaborative training!", "La Marche en convoi ne prend pas en charge l'entraînement collaboratif !", "Марш колонной не поддерживает совместную тренировку!" } }, { "{0}科目成功下发!", new[] { "{0}科目成功下发!", "{0} subject sent successfully!", "Sujet {0} envoyé avec succès !", "Задание {0} успешно отправлено!" } }, { "未选择想定文件!", new[] { "未选择想定文件!", "No scenario file selected!", "Aucun fichier scénario sélectionné !", "Файл сценария не выбран!" } }, { "未选择有效科目!", new[] { "未选择有效科目!", "No valid subject selected!", "Aucun sujet valide sélectionné !", "Не выбрано допустимое задание!" } }, { "学员:{0} 完成{1}科目({2}) 用时:{3}", new[] { "学员:{0} 完成{1}科目({2}) 用时:{3}", "Student: {0} completed {1} subject ({2}) duration: {3}", "Stagiaire : {0} a terminé le sujet {1} ({2}) durée : {3}", "Обучаемый: {0} завершил задание {1} ({2}) время: {3}" } }, { "{0} {1}完成{2}科目:{3}", new[] { "{0} {1}完成{2}科目:{3}", "{0} {1} completed {2} subject: {3}", "{0} {1} a terminé le sujet {2} : {3}", "{0} {1} завершил задание {2}: {3}" } }, { "用时:{0}", new[] { "用时:{0}", "Duration: {0}", "Durée : {0}", "Продолжительность: {0}" } }, { "录屏视频:{0}", new[] { "录屏视频:{0}", "Recording video: {0}", "Vidéo enregistrée : {0}", "Видео записи: {0}" } }, { "录屏视频:{0}\r\n(视频文件已丢失,无法播放!)", new[] { "录屏视频:{0}\r\n(视频文件已丢失,无法播放!)", "Recording video: {0}\r\n(Video file is missing and cannot be played!)", "Vidéo enregistrée : {0}\r\n(Le fichier vidéo est manquant et ne peut pas être lu !)", "Видео записи: {0}\r\n(Видеофайл отсутствует и не может быть воспроизведён!)" } }, { "录屏视频:无", new[] { "录屏视频:无", "Recording video: None", "Vidéo enregistrée : aucune", "Видео записи: нет" } }, { "遇到突发事件:{0}", new[] { "遇到突发事件:{0}", "Incident encountered: {0}", "Incident rencontré : {0}", "Возник инцидент: {0}" } }, { "选择处理方式:{0}", new[] { "选择处理方式:{0}", "Selected response: {0}", "Réponse sélectionnée : {0}", "Выбранное действие: {0}" } }, { "VR设备启动失败,无法进行虚拟维修,请检查设备后重试!", new[] { "VR设备启动失败,无法进行虚拟维修,请检查设备后重试!", "VR device failed to start. Virtual repair cannot continue; check the device and try again!", "Le périphérique VR n'a pas démarré. La réparation virtuelle ne peut pas continuer ; vérifiez le périphérique et réessayez !", "Не удалось запустить VR-устройство. Виртуальный ремонт невозможен; проверьте устройство и повторите попытку!" } }, { "{0}{1}", new[] { "{0}{1}", "{0} {1}", "{0} {1}", "{0} {1}" } }, { "(行军中)", new[] { "(行军中)", "(Marching)", "(En marche)", "(В марше)" } }, { "({0})", new[] { "({0})", "({0})", "({0})", "({0})" } }, { "{0}不应当编入{1}", new[] { "{0}不应当编入{1}", "{0} should not be assigned to {1}.", "{0} ne doit pas être affecté à {1}.", "{0} не следует включать в {1}." } }, { "想定文件生成成功!文件路径为:{0}", new[] { "想定文件生成成功!文件路径为:{0}", "Scenario file created successfully! File path: {0}", "Fichier scénario créé avec succès ! Chemin : {0}", "Файл сценария успешно создан! Путь: {0}" } }, // Duration format strings (stored as total seconds, localized at display time) { "详细数据", new[] { "详细数据", "Details", "Détails", "Подробные данные" } }, { "{0}分:{1}秒", new[] { "{0}分:{1}秒", "{0} min {1} sec", "{0} min {1} s", "{0} мин {1} с" } }, { "{0}小时{1}分{2}秒", new[] { "{0}小时{1}分{2}秒", "{0} hr {1} min {2} sec", "{0} h {1} min {2} s", "{0} ч {1} мин {2} с" } }, { "用时:{0}分:{1}秒", new[] { "用时:{0}分:{1}秒", "Duration: {0} min {1} sec", "Durée : {0} min {1} s", "Продолжительность: {0} мин {1} с" } }, { "用时:{0}小时{1}分{2}秒", new[] { "用时:{0}小时{1}分{2}秒", "Duration: {0} hr {1} min {2} sec", "Durée : {0} h {1} min {2} s", "Продолжительность: {0} ч {1} мин {2} с" } }, { "学员:{0} 完成{1}科目({2}) 用时:{3}分:{4}秒", new[] { "学员:{0} 完成{1}科目({2}) 用时:{3}分:{4}秒", "Student: {0} completed {1} subject ({2}) duration: {3} min {4} sec", "Stagiaire : {0} a terminé le sujet {1} ({2}) durée : {3} min {4} s", "Обучаемый: {0} завершил задание {1} ({2}) время: {3} мин {4} с" } }, { "学员:{0} 完成{1}科目({2}) 用时:{3}小时{4}分{5}秒", new[] { "学员:{0} 完成{1}科目({2}) 用时:{3}小时{4}分{5}秒", "Student: {0} completed {1} subject ({2}) duration: {3} hr {4} min {5} sec", "Stagiaire : {0} a terminé le sujet {1} ({2}) durée : {3} h {4} min {5} s", "Обучаемый: {0} завершил задание {1} ({2}) время: {3} ч {4} мин {5} с" } }, { "Enter text...", new[] { "Enter text...", "Enter text...", "Saisir...", "Введите текст..." } }, { "当前科目:编队行军", new[] { "当前科目:编队行军", "Current Subject: Convoy March", "Sujet actuel : Marche en convoi", "Текущее задание: Марш колонной" } }, { "当前科目:修理所展开", new[] { "当前科目:修理所展开", "Current Subject: Repair Site Deployment", "Sujet actuel : Déploiement du site de réparation", "Текущее задание: Развёртывание ремонтного пункта" } }, { "当前科目:装备维修", new[] { "当前科目:装备维修", "Current Subject: Equipment Maintenance", "Sujet actuel : Maintenance des équipements", "Текущее задание: Техническое обслуживание" } }, // Operation detail message templates (used by EditorAppraiser) { "{0}增加{1}等{2}种车型,扣{3}分", new[] { "{0}增加{1}等{2}种车型,扣{3}分", "{0} added {1} etc. {2} vehicle types, deduct {3} points", "{0} a ajouté {1} etc. {2} types de véhicules, déduction de {3} points", "{0} добавлено {1} и др. {2} типов машин, вычет {3} баллов" } }, { "{0}缺少标准车型:{1},扣{2}分", new[] { "{0}缺少标准车型:{1},扣{2}分", "{0} missing standard vehicle: {1}, deduct {2} points", "{0} véhicule standard manquant : {1}, déduction de {2} points", "{0} отсутствует стандартная машина: {1}, вычет {2} баллов" } }, { "指挥组仅有一台分队指挥车,扣3分", new[] { "指挥组仅有一台分队指挥车,扣3分", "Command group has only one command vehicle, deduct 3 points", "Le groupe de commandement n'a qu'un seul véhicule de commandement, déduction de 3 points", "В группе управления только одна командная машина, вычет 3 баллов" } }, { "{0}装备数量为{1}台,超出{2}台,扣{3}分", new[] { "{0}装备数量为{1}台,超出{2}台,扣{3}分", "{0} equipment count is {1}, exceeds {2}, deduct {3} points", "{0} le nombre d'équipements est {1}, dépasse {2}, déduction de {3} points", "{0} количество техники {1}, превышает {2}, вычет {3} баллов" } }, { "{0}人员工种缺少{1},扣{2}分", new[] { "{0}人员工种缺少{1},扣{2}分", "{0} missing personnel types: {1}, deduct {2} points", "{0} types de personnel manquants : {1}, déduction de {2} points", "{0} отсутствуют типы специалистов: {1}, вычет {2} баллов" } }, { "{0}人员工种缺少{1}\u201C等\u201D{2}种,扣{3}分", new[] { "{0}人员工种缺少{1}\u201C等\u201D{2}种,扣{3}分", "{0} missing personnel types: {1} etc. {2} types, deduct {3} points", "{0} types de personnel manquants : {1} etc. {2} types, déduction de {3} points", "{0} отсутствуют типы специалистов: {1} и др. {2} типов, вычет {3} баллов" } }, { "{0}人员工种增加:{1}\u201C等\u201D{2}种,扣{3}分", new[] { "{0}人员工种增加:{1}\u201C等\u201D{2}种,扣{3}分", "{0} added personnel types: {1} etc. {2} types, deduct {3} points", "{0} types de personnel ajoutés : {1} etc. {2} types, déduction de {3} points", "{0} добавлены типы специалистов: {1} и др. {2} типов, вычет {3} баллов" } }, { "{0}{1}人数为{2},少于{3}人,扣{4}分", new[] { "{0}{1}人数为{2},少于{3}人,扣{4}分", "{0} {1} count is {2}, less than {3}, deduct {4} points", "{0} nombre de {1} est {2}, inférieur à {3}, déduction de {4} points", "{0} количество {1} равно {2}, меньше {3}, вычет {4} баллов" } }, { "当前场景无水源,不计算洗消场与水源间距扣分项", new[] { "当前场景无水源,不计算洗消场与水源间距扣分项", "No water source in the current scene, skip decontamination area distance deduction", "Aucune source d'eau dans la scène actuelle, déduction de distance de la zone de décontamination ignorée", "В текущей сцене нет источника воды, вычет за расстояние до зоны дезактивации пропущен" } }, { "洗消场与水源间距为{0}M,大于100M,每10米扣0.05f,计扣{1}分", new[] { "洗消场与水源间距为{0}M,大于100M,每10米扣0.05f,计扣{1}分", "Decontamination area to water source distance is {0}M, exceeds 100M, deduct 0.05 per 10M, total deduction {1} points", "Distance zone de décontamination / source d'eau : {0}M, supérieure à 100M, déduction 0.05 par 10M, total {1} points", "Расстояние от зоны дезактивации до источника воды {0}м, более 100м, вычет 0.05 за 10м, итого {1} баллов" } }, { "{0}与{1}间距为{2}M,小于200M,扣1分", new[] { "{0}与{1}间距为{2}M,小于200M,扣1分", "Distance between {0} and {1} is {2}M, less than 200M, deduct 1 point", "Distance entre {0} et {1} : {2}M, inférieure à 200M, déduction de 1 point", "Расстояние между {0} и {1}: {2}м, менее 200м, вычет 1 балл" } }, { "{0}与{1}间距为{2}M,小于100M,扣1分", new[] { "{0}与{1}间距为{2}M,小于100M,扣1分", "Distance between {0} and {1} is {2}M, less than 100M, deduct 1 point", "Distance entre {0} et {1} : {2}M, inférieure à 100M, déduction de 1 point", "Расстояние между {0} и {1}: {2}м, менее 100м, вычет 1 балл" } }, { "指控区与修理场间距为{0}M,小于300M,每50米扣0.5f,计扣{1}分", new[] { "指控区与修理场间距为{0}M,小于300M,每50米扣0.5f,计扣{1}分", "Command area to repair site distance is {0}M, less than 300M, deduct 0.5 per 50M, total {1} points", "Distance zone de commandement / site de réparation : {0}M, inférieure à 300M, déduction 0.5 par 50M, total {1} points", "Расстояние от зоны управления до ремонтного участка {0}м, менее 300м, вычет 0.5 за 50м, итого {1} баллов" } }, { "指控区与修理场间距为{0}M,大于600M,每50米扣0.5f,计扣{1}分", new[] { "指控区与修理场间距为{0}M,大于600M,每50米扣0.5f,计扣{1}分", "Command area to repair site distance is {0}M, exceeds 600M, deduct 0.5 per 50M, total {1} points", "Distance zone de commandement / site de réparation : {0}M, supérieure à 600M, déduction 0.5 par 50M, total {1} points", "Расстояние от зоны управления до ремонтного участка {0}м, более 600м, вычет 0.5 за 50м, итого {1} баллов" } }, { "器材存放场与修理场间距为{0}M,大于50M,每10米扣0.05f,计扣{1}分", new[] { "器材存放场与修理场间距为{0}M,大于50M,每10米扣0.05f,计扣{1}分", "Equipment storage to repair site distance is {0}M, exceeds 50M, deduct 0.05 per 10M, total {1} points", "Distance entre le dépôt de matériel et le site de réparation : {0}M, supérieure à 50M, déduction 0.05 par 10M, total {1} points", "Расстояние от склада оборудования до ремонтного участка {0}м, более 50м, вычет 0.05 за 10м, итого {1} баллов" } }, { "{0}中{1}与{2}间距为{3}M,小于50M,扣0.5分", new[] { "{0}中{1}与{2}间距为{3}M,小于50M,扣0.5分", "In {0}, distance between {1} and {2} is {3}M, less than 50M, deduct 0.5 points", "Dans {0}, distance entre {1} et {2} : {3}M, inférieure à 50M, déduction de 0.5 points", "В {0} расстояние между {1} и {2}: {3}м, менее 50м, вычет 0.5 балла" } }, { "存在未安置装备的厂区,无法判定距离和转运时间!", new[] { "存在未安置装备的厂区,无法判定距离和转运时间!", "Some areas have no equipment placed, cannot determine distance and transport time!", "Certaines zones n'ont pas d'équipement placé, impossible de déterminer la distance et le temps de transport !", "Некоторые зоны без размещённой техники, невозможно определить расстояние и время транспортировки!" } }, { "按照15km/h速度计算转运时间:", new[] { "按照15km/h速度计算转运时间:", "Transport time calculated at 15km/h:", "Temps de transport calculé à 15km/h :", "Время транспортировки рассчитано при 15км/ч:" } }, { "修理厂转运总用时:{0}时{1}分{2}秒", new[] { "修理厂转运总用时:{0}时{1}分{2}秒", "Total repair site transport time: {0}h {1}m {2}s", "Temps total de transport du site de réparation : {0}h {1}m {2}s", "Общее время транспортировки ремонтного пункта: {0}ч {1}мин {2}с" } }, { "{0}距离{1}:{2}米,预计转运用时:{3}秒", new[] { "{0}距离{1}:{2}米,预计转运用时:{3}秒", "{0} to {1}: {2}m, estimated transport time: {3}s", "{0} à {1} : {2}m, temps de transport estimé : {3}s", "{0} до {1}: {2}м, расчётное время транспортировки: {3}с" } }, { "{0}增加车型:{1}\u201C等\u201D{2}种,扣{3}分", new[] { "{0}增加车型:{1}\u201C等\u201D{2}种,扣{3}分", "{0} added vehicle types: {1} etc. {2} types, deduct {3} points", "{0} types de véhicules ajoutés : {1} etc. {2} types, déduction de {3} points", "{0} добавлены типы машин: {1} и др. {2} типов, вычет {3} баллов" } } }; [SerializeField] private int language; private Font font; public static UILanguage Language { get { Ensure(); return (UILanguage)instance.language; } } public static event Action LanguageChanged; public static Font UIFont { get { Ensure(); return instance.font; } } public static void Ensure() { if (instance != null) return; GameObject go = new GameObject("LocalizationManager"); instance = go.AddComponent(); DontDestroyOnLoad(go); } private void Awake() { if (instance != null && instance != this) { Destroy(gameObject); return; } instance = this; language = Mathf.Clamp(PlayerPrefs.GetInt(PreferenceKey, 0), 0, 3); font = Resources.Load(FontResourcePath); } private void Start() { RefreshAll(); } private int refreshFrameCounter = 0; private void LateUpdate() { // Covers canvases instantiated after the current frame and avoids duplicate bars. LocalizationLanguageTestBar.EnsureForActiveCanvases(); // Periodically refresh localization for dynamically loaded UI (e.g. student panels). if (++refreshFrameCounter >= 30) { refreshFrameCounter = 0; RefreshAll(); } } public static void SetLanguage(int value) { Ensure(); instance.language = Mathf.Clamp(value, 0, 3); PlayerPrefs.SetInt(PreferenceKey, instance.language); PlayerPrefs.Save(); instance.RefreshAll(); if (LanguageChanged != null) LanguageChanged(); } public static string Get(string source) { Ensure(); return instance.Translate(source); } public static string Format(string source, params object[] args) { return string.Format(Get(source), args); } public static string DisplayName(string businessValue) { return Get(businessValue); } // Assign a localized formatted value and retain its source plus arguments for language changes. public static void SetFormatted(Text text, string source, params object[] args) { if (text == null) return; Ensure(); int id = text.GetInstanceID(); TextState state; if (!instance.textStates.TryGetValue(id, out state)) { state = new TextState(); instance.textStates.Add(id, state); } state.source = source; state.formatArgs = args; state.localized = Format(source, args); text.text = state.localized; } /// /// Parse a duration string (total seconds or old Chinese format) and set the Text with localized format. /// public static void SetDuration(Text text, string secondsStr) { if (text == null) return; int totalSeconds; if (int.TryParse(secondsStr, out totalSeconds)) { // New format: total seconds as string. } else { totalSeconds = ParseChineseDuration(secondsStr); if (totalSeconds < 0) { text.text = secondsStr; return; } } int h = totalSeconds / 3600; int m = (totalSeconds % 3600) / 60; int s = totalSeconds % 60; if (h > 0) SetFormatted(text, "{0}小时{1}分{2}秒", h, m, s); else SetFormatted(text, "{0}分:{1}秒", m, s); } /// /// Localize a stored operation message. Messages stored with \x01 prefix use key+args format. /// Old messages without the prefix are returned as-is. /// public static string LocalizeOperateMsg(string stored) { if (string.IsNullOrEmpty(stored) || stored[0] != '\x01') return stored; string[] parts = stored.Substring(1).Split('\x02'); string key = parts[0]; if (parts.Length > 1) { object[] args = new object[parts.Length - 1]; for (int i = 0; i < args.Length; i++) args[i] = parts[i + 1]; return string.Format(Format(key, args), instance.TranslateArgs(args)); } return Get(key); } public static int ParseChineseDuration(string s) { if (string.IsNullOrEmpty(s)) return -1; int hours = 0, minutes = 0, seconds = 0; bool found = false; int hourIdx = s.IndexOf("小时"); int minIdx = s.IndexOf("分"); int secIdx = s.IndexOf("秒"); if (hourIdx >= 0 && int.TryParse(s.Substring(0, hourIdx).Trim(), out hours)) found = true; if (minIdx >= 0) { int start = hourIdx >= 0 ? hourIdx + 2 : 0; string minPart = s.Substring(start, minIdx - start).Trim(':', ' '); if (int.TryParse(minPart, out minutes)) found = true; } if (secIdx >= 0) { int start = minIdx >= 0 ? minIdx + 1 : 0; string secPart = s.Substring(start, secIdx - start).Trim(':', ' '); if (int.TryParse(secPart, out seconds)) found = true; } return found ? hours * 3600 + minutes * 60 + seconds : -1; } public void RefreshAll() { Text[] texts = Resources.FindObjectsOfTypeAll(); for (int i = 0; i < texts.Length; i++) Localize(texts[i]); Dropdown[] dropdowns = Resources.FindObjectsOfTypeAll(); for (int i = 0; i < dropdowns.Length; i++) Localize(dropdowns[i]); } private string Translate(string source) { source = GetSourceText(source); if (string.IsNullOrEmpty(source) || language == (int)UILanguage.Chinese) return source; string[] values; return table.TryGetValue(source, out values) ? values[language] : source; } private string GetSourceText(string value) { if (string.IsNullOrEmpty(value) || table.ContainsKey(value)) return value; foreach (KeyValuePair pair in table) { for (int i = 1; i < pair.Value.Length; i++) { if (pair.Value[i] == value) return pair.Key; } } return value; } private void Localize(Text text) { if (text == null || !text.gameObject.scene.IsValid()) return; // Dropdown caption and item texts are handled by Localize(Dropdown). Dropdown dropdown = text.GetComponentInParent(); if (dropdown != null && (dropdown.captionText == text || dropdown.itemText == text)) return; // InputField children are managed by their owning panels to avoid // interfering with user input and placeholder rendering. if (text.GetComponentInParent() != null) return; if (font != null) { Color savedColor = text.color; text.font = font; text.color = savedColor; text.verticalOverflow = VerticalWrapMode.Overflow; } int id = text.GetInstanceID(); TextState state; if (!textStates.TryGetValue(id, out state)) { state = new TextState { source = text.text, localized = text.text }; textStates.Add(id, state); } else if (text.text != state.localized) { state.source = GetSourceText(text.text); state.formatArgs = null; } state.localized = state.formatArgs == null ? Translate(state.source) : string.Format(Translate(state.source), TranslateArgs(state.formatArgs)); text.text = state.localized; } private object[] TranslateArgs(object[] args) { if (args == null) return null; object[] result = new object[args.Length]; for (int i = 0; i < args.Length; i++) { result[i] = args[i] is string ? (object)Translate((string)args[i]) : args[i]; } return result; } private void Localize(Dropdown dropdown) { if (dropdown == null || !dropdown.gameObject.scene.IsValid()) return; int id = dropdown.GetInstanceID(); DropdownState state; if (!dropdownStates.TryGetValue(id, out state)) { state = new DropdownState(); dropdownStates.Add(id, state); } bool optionsChanged = state.sources.Count != dropdown.options.Count; if (!optionsChanged) { for (int i = 0; i < dropdown.options.Count; i++) { if (dropdown.options[i].text != state.localized[i]) { optionsChanged = true; break; } } } if (optionsChanged) { state.sources.Clear(); for (int i = 0; i < dropdown.options.Count; i++) state.sources.Add(dropdown.options[i].text); } state.localized.Clear(); for (int i = 0; i < dropdown.options.Count; i++) { string translated = Translate(state.sources[i]); state.localized.Add(translated); dropdown.options[i].text = translated; } if (font != null) { Text[] texts = dropdown.GetComponentsInChildren(true); for (int i = 0; i < texts.Length; i++) { Color savedColor = texts[i].color; texts[i].font = font; texts[i].color = savedColor; texts[i].verticalOverflow = VerticalWrapMode.Overflow; } } dropdown.RefreshShownValue(); } }