frontAnswerer/src/i18n/i18nWidget.ts
2025-08-12 04:35:49 +03:00

327 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
// 1. Функция для определения языка из URL
const getLanguageFromURL = (): string => {
const path = window.location.pathname;
const langMatch = path.match(/^\/(en|ru|uz)(\/|$)/i);
const detectedLang = langMatch ? langMatch[1].toLowerCase() : "ru"; // Фолбэк на 'ru'
console.log("🔍 Widget i18n: Detected language from URL:", detectedLang, "path:", path);
return detectedLang;
};
// 2. Локали, встроенные прямо в конфиг
const r = {
ru: {
translation: {
"quiz is inactive": "Квиз не активирован",
"no questions found": "Нет созданных вопросов",
"quiz is empty": "Квиз пуст",
"quiz already completed": "Вы уже прошли этот опрос",
"no quiz id": "Отсутствует id квиза",
"quiz data is null": "Не были переданы параметры квиза",
"invalid request data": "Такого квиза не существует",
"default message": "Что-то пошло не так",
"The request could not be sent": "Заявка не может быть отправлена",
"The number of points could not be sent": "Количество баллов не может быть отправлено",
"Your result": "Ваш результат",
"Your points": "Ваши баллы",
of: "из",
"View answers": "Посмотреть ответы",
"Find out more": "Узнать подробнее",
"Go to website": "Перейти на сайт",
"Question title": "Заголовок вопроса",
"Question without a title": "Вопрос без названия",
"Your answer": "Ваш ответ",
"Add image": "Добавить изображение",
"Accepts images": "Принимает изображения",
"Add video": "Добавить видео",
"Accepts .mp4 and .mov format - maximum 50mb": "Принимает .mp4 и .mov формат — максимум 50мб",
"Add audio file": "Добавить аудиофайл",
"Accepts audio files": "Принимает аудиофайлы",
"Add document": "Добавить документ",
"Accepts documents": "Принимает документы",
Next: "Далее",
Prev: "Назад",
From: "От",
До: "До",
"Enter your answer": "Введите свой ответ",
"Incorrect file type selected": "Выбран некорректный тип файла",
"File is too big. Maximum size is 50 MB": "Файл слишком большой. Максимальный размер 50 МБ",
"Acceptable file extensions": "Допустимые расширения файлов",
"You have uploaded": "Вы загрузили",
"The answer was not counted": "Ответ не был засчитан",
"Select an answer option below": "Выберите вариант ответа ниже",
"Select an answer option on the left": "Выберите вариант ответа слева",
"Fill out the form to receive your test results": "Заполните форму, чтобы получить результаты теста",
Enter: "Введите",
Name: "Имя",
"Phone number": "Номер телефона",
"Last name": "Фамилия",
Address: "Адрес",
"Incorrect email entered": "Введена некорректная почта",
"Please fill in the fields": "Пожалуйста, заполните поля",
"Please try again later": "повторите попытку позже",
"Regulation on the processing of personal data": "Положением об обработке персональных данных",
"Privacy Policy": "Политикой конфиденциальности",
familiarized: "ознакомлен",
and: "и",
"Get results": "Получить результаты",
"Data sent successfully": "Данные успешно отправлены",
Step: "Шаг",
"questions are not ready yet": "Вопросы для аудитории пока не готовы. Подождите",
"Add your image": "Добавьте своё изображение",
"select emoji": "выберите смайлик",
"Please complete the phone number": "Пожалуйста, заполните номер телефона до конца",
"": "", // Пустой ключ для fallback
},
},
en: {
translation: {
"quiz is inactive": "Quiz is inactive",
"no questions found": "No questions found",
"quiz is empty": "Quiz is empty",
"quiz already completed": "You've already completed this quiz",
"no quiz id": "Missing quiz ID",
"quiz data is null": "No quiz parameters were provided",
"invalid request data": "This quiz doesn't exist",
"default message": "Something went wrong",
"The request could not be sent": "Request could not be sent",
"The number of points could not be sent": "Points could not be submitted",
"Your result": "Your result",
"Your points": "Your points",
of: "of",
"View answers": "View answers",
"Find out more": "Learn more",
"Go to website": "Go to website",
"Question title": "Question title",
"Question without a title": "Untitled question",
"Your answer": "Your answer",
"Add image": "Add image",
"Accepts images": "Accepts images",
"Add video": "Add video",
"Accepts .mp4 and .mov format - maximum 50mb": "Accepts .mp4 and .mov format - maximum 50MB",
"Add audio file": "Add audio file",
"Accepts audio files": "Accepts audio files",
"Add document": "Add document",
"Accepts documents": "Accepts documents",
Next: "Next",
Prev: "Previous",
From: "From",
До: "To",
"Enter your answer": "Enter your answer",
"Incorrect file type selected": "Invalid file type selected",
"File is too big. Maximum size is 50 MB": "File is too large. Maximum size is 50 MB",
"Acceptable file extensions": "Allowed file extensions",
"You have uploaded": "You've uploaded",
"The answer was not counted": "Answer wasn't counted",
"Select an answer option below": "Select an answer option below",
"Select an answer option on the left": "Select an answer option on the left",
"Fill out the form to receive your test results": "Fill out the form to receive your test results",
Enter: "Enter",
Name: "Name",
"Phone number": "Phone number",
"Last name": "Last name",
Address: "Address",
"Incorrect email entered": "Invalid email entered",
"Please fill in the fields": "Please fill in the fields",
"Please try again later": "Please try again later",
"Regulation on the processing of personal data": "Personal Data Processing Regulation",
"Privacy Policy": "Privacy Policy",
familiarized: "acknowledged",
and: "and",
"Get results": "Get results",
"Data sent successfully": "Data sent successfully",
Step: "Step",
"questions are not ready yet": "There are no questions for the audience yet. Please wait",
"Add your image": "Add your image",
"select emoji": "select emoji",
"Please complete the phone number": "Please complete the phone number",
"": "", // Пустой ключ для fallback
},
},
uz: {
translation: {
"quiz is inactive": "Test faol emas",
"no questions found": "Savollar topilmadi",
"quiz is empty": "Test boʻsh",
"quiz already completed": "Siz bu testni allaqachon topshirgansiz",
"no quiz id": "Test IDsi yoʻq",
"quiz data is null": "Test parametrlari yuborilmagan",
"invalid request data": "Bunday test mavjud emas",
"default message": "Xatolik yuz berdi",
"The request could not be sent": "Soʻrov yuborib boʻlmadi",
"The number of points could not be sent": "Ballar yuborib boʻlmadi",
"Your result": "Sizning natijangiz",
"Your points": "Sizning ballaringiz",
of: "/",
"View answers": "Javoblarni koʻrish",
"Find out more": "Batafsil maʼlumot",
"Go to website": "Veb-saytga oʻtish",
"Question title": "Savol sarlavhasi",
"Question without a title": "Sarlavhasiz savol",
"Your answer": "Sizning javobingiz",
"Add image": "Rasm qoʻshish",
"Accepts images": "Rasmlarni qabul qiladi",
"Add video": "Video qoʻshish",
"Accepts .mp4 and .mov format - maximum 50mb": ".mp4 va .mov formatlarini qabul qiladi - maksimal 50MB",
"Add audio file": "Audio fayl qoʻshish",
"Accepts audio files": "Audio fayllarni qabul qiladi",
"Add document": "Hujjat qoʻshish",
"Accepts documents": "Hujjatlarni qabul qiladi",
Next: "Keyingi",
Prev: "Oldingi",
From: "Dan",
До: "Gacha",
"Enter your answer": "Javobingizni kiriting",
"Incorrect file type selected": "Notoʻgʻri fayl turi tanlandi",
"File is too big. Maximum size is 50 MB": "Fayl juda katta. Maksimal hajmi 50 MB",
"Acceptable file extensions": "Qabul qilinadigan fayl kengaytmalari",
"You have uploaded": "Siz yuklagansiz",
"The answer was not counted": "Javob hisobga olinmadi",
"Select an answer option below": "Quyidagi javob variantlaridan birini tanlang",
"Select an answer option on the left": "Chapdagi javob variantlaridan birini tanlang",
"Fill out the form to receive your test results": "Test natijalaringizni olish uchun shaklni toʻldiring",
Enter: "Kiriting",
Name: "Ism",
"Phone number": "Telefon raqami",
"Last name": "Familiya",
Address: "Manzil",
"Incorrect email entered": "Notoʻgʻri elektron pochta kiritildi",
"Please fill in the fields": "Iltimos, maydonlarni toʻldiring",
"Please try again later": "Iltimos, keyinroq urinib koʻring",
"Regulation on the processing of personal data": "Shaxsiy maʼlumotlarni qayta ishlash qoidalari",
"Privacy Policy": "Maxfiylik siyosati",
familiarized: "tanishdim",
and: "va",
"Get results": "Natijalarni olish",
"Data sent successfully": "Ma'lumotlar muvaffaqiyatli yuborildi",
Step: "Qadam",
"questions are not ready yet": "Tomoshabinlar uchun hozircha savollar yo'q. Iltimos kuting",
"Add your image": "Rasmingizni qo'shing",
"select emoji": "emoji tanlang",
"Please complete the phone number": "Iltimos, telefon raqamini to'liq kiriting",
"": "", // Пустой ключ для fallback
},
},
};
console.log("🚀 Widget i18n: Starting initialization...");
console.log("🔍 Widget i18n: i18next instance before init:", i18n);
console.log("🔍 Widget i18n: i18next isInitialized before init:", i18n.isInitialized);
// Проверяем, не инициализирован ли уже i18n
if (i18n.isInitialized) {
console.log("⚠️ Widget i18n: i18n already initialized, adding resources to existing instance");
// Добавляем ресурсы к существующему экземпляру
(Object.keys(r) as Array<"ru" | "en" | "uz">).forEach((lng) => {
if (i18n.store.data[lng] && i18n.store.data[lng].translation) {
// Объединяем с существующими переводами
i18n.store.data[lng].translation = {
...(i18n.store.data[lng].translation as Record<string, string>),
...r[lng].translation,
};
} else {
// Добавляем новые переводы
i18n.store.data[lng] = {
...(i18n.store.data[lng] as Record<string, any>),
translation: r[lng].translation,
};
}
});
console.log("✅ Widget i18n: Resources added to existing i18n instance");
console.log("🔍 Widget i18n: Testing translations after adding resources:");
console.log("🔍 Widget i18n: t('Step'):", i18n.t("Step"));
console.log("🔍 Widget i18n: t('of'):", i18n.t("of"));
console.log("🔍 Widget i18n: t('Prev'):", i18n.t("Prev"));
console.log("🔍 Widget i18n: t('Next'):", i18n.t("Next"));
} else {
// 3. Конфигурация i18n без Backend
i18n
.use(initReactI18next)
.init({
resources: r, // Используем встроенные переводы
lng: getLanguageFromURL(),
fallbackLng: "ru",
supportedLngs: ["en", "ru", "uz"],
debug: true,
interpolation: {
escapeValue: false,
},
react: {
useSuspense: false,
},
detection: {
order: ["path"],
lookupFromPathIndex: 0,
caches: [],
},
parseMissingKeyHandler: (key) => {
console.warn("⚠️ Widget i18n: Missing translation key:", key);
return key;
},
missingKeyHandler: (lngs, ns, key) => {
console.error("🚨 Widget i18n: Missing i18n key:", {
key,
languages: lngs,
namespace: ns,
stack: new Error().stack,
});
},
})
.then(() => {
console.log("✅ Widget i18n: Initialization completed successfully");
console.log("🔍 Widget i18n: Current language:", i18n.language);
console.log("🔍 Widget i18n: Available languages:", i18n.languages);
console.log("🔍 Widget i18n: Available keys for ru:", Object.keys(r.ru.translation));
console.log("🔍 Widget i18n: Available keys for en:", Object.keys(r.en.translation));
console.log("🔍 Widget i18n: Available keys for uz:", Object.keys(r.uz.translation));
console.log("🔍 Widget i18n: Looking for keys: Step, of, Prev, Next");
console.log("🔍 Widget i18n: Step in ru:", r.ru.translation.Step);
console.log("🔍 Widget i18n: of in ru:", r.ru.translation.of);
console.log("🔍 Widget i18n: Prev in ru:", r.ru.translation.Prev);
console.log("🔍 Widget i18n: Next in ru:", r.ru.translation.Next);
// Проверяем, что ключи доступны через i18n
console.log("🔍 Widget i18n: Testing translations through i18n:");
console.log("🔍 Widget i18n: t('Step'):", i18n.t("Step"));
console.log("🔍 Widget i18n: t('of'):", i18n.t("of"));
console.log("🔍 Widget i18n: t('Prev'):", i18n.t("Prev"));
console.log("🔍 Widget i18n: t('Next'):", i18n.t("Next"));
// Проверяем состояние i18n
console.log("🔍 Widget i18n: i18n.isInitialized:", i18n.isInitialized);
console.log("🔍 Widget i18n: i18n.store.data:", i18n.store.data);
console.log("🔍 Widget i18n: i18n.store.options:", i18n.store.options);
})
.catch((error) => {
console.error("❌ Widget i18n: Initialization failed:", error);
});
}
// 4. Логирование событий
i18n.on("languageChanged", (lng) => {
console.log("🔄 Widget i18n: Language changed to:", lng);
});
i18n.on("initialized", (options) => {
console.log("🎯 Widget i18n: Initialized event fired with options:", options);
});
i18n.on("loaded", (loaded) => {
console.log("📦 Widget i18n: Loaded event fired:", loaded);
});
i18n.on("failedLoading", (lng, ns, msg) => {
console.error("💥 Widget i18n: Failed loading:", { lng, ns, msg });
});
i18n.on("missingKey", (lngs, namespace, key, res) => {
console.warn("⚠️ Widget i18n: Missing key event:", { lngs, namespace, key, res });
});
export default i18n;