diff --git a/src/i18n/i18n.ts b/src/i18n/i18n.ts index e4f8067..efda870 100644 --- a/src/i18n/i18n.ts +++ b/src/i18n/i18n.ts @@ -18,11 +18,197 @@ const getLanguageFromURL = (): string => { return "ru"; // Жёсткий фолбэк }; +const r = { + ru: { + "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": "выберите смайлик", + "file is too big": "Файл слишком большой", + "file type is not supported": "Тип файла не поддерживается", + }, + en: { + "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", + }, + uz: { + "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", + }, +}; + // 2. Конфиг с полной отладкой i18n .use(Backend) .use(initReactI18next) .init({ + resources: r, lng: getLanguageFromURL(), // Принудительно из URL fallbackLng: "ru", supportedLngs: ["en", "ru", "uz"], diff --git a/src/i18n/i18nWidget.ts b/src/i18n/i18nWidget.ts new file mode 100644 index 0000000..693e57a --- /dev/null +++ b/src/i18n/i18nWidget.ts @@ -0,0 +1,240 @@ +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); + return langMatch ? langMatch[1].toLowerCase() : "ru"; // Фолбэк на 'ru' +}; + +// 2. Локали, встроенные прямо в конфиг + +const r = { + ru: { + "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": "выберите смайлик", + "file is too big": "Файл слишком большой", + "file type is not supported": "Тип файла не поддерживается", + }, + en: { + "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", + }, + uz: { + "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", + }, +}; + +// 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("Missing translation:", key); + return key; + }, + missingKeyHandler: (lngs, ns, key) => { + console.error("🚨 Missing i18n key:", { + key, + languages: lngs, + namespace: ns, + stack: new Error().stack, + }); + }, + }) + .then(() => { + console.log("i18n initialized. Current language:", i18n.language); + }); + +// 4. Логирование событий +i18n.on("languageChanged", (lng) => { + console.log("Language changed to:", lng); +}); + +export default i18n; diff --git a/src/widget.tsx b/src/widget.tsx index 653e35b..97c62d8 100644 --- a/src/widget.tsx +++ b/src/widget.tsx @@ -2,6 +2,7 @@ import QuizAnswerer from "@/components/QuizAnswerer"; import { createRoot } from "react-dom/client"; // eslint-disable-next-line react-refresh/only-export-components export * from "./widgets"; +import "./i18n/i18nWidget"; // old widget const widget = { @@ -19,7 +20,13 @@ const widget = { const root = createRoot(element); - root.render(); + root.render( + + ); }, };