PageSourceSearch

https://english-step-by-step.com/js/i18n.js

js english-step-by-step.com collected 2026-10-02 00:49:03 UTC 48,687 bytes, 671 lines download raw bytes

1import { getLanguage, setLanguage } from './storage.js';
2
3export const messages = {
4  ru: {
5    siteTitle: 'Курс английского языка',
6    homeSiteTitle: 'Learn English Easily — учите английский шаг за шагом',
7    homeEyebrow: 'Уроки и разговорная практика',
8    homeTopicsTitle: 'Английский шаг за шагом',
9    homeTopicsTitleLead: 'Английский',
10    homeTopicsTitleLine2: 'шаг за шагом',
11    homeTopicsSubtitle: 'Разбирайтесь в грамматике, учите новые слова и тренируйте разговорную речь. Выберите тему и начните учиться бесплатно.',
12    homeLearningStart: 'Начните с первого урока',
13    homeLearningContinue: 'Продолжите, где остановились',
14    homeLearningStartNote: 'Можно начать без регистрации',
15    homeLearningContinueNote: 'Последние открытые уроки в этом браузере',
16    homeLessonFirst: 'Первый урок',
17    homeLessonRecent: 'Вы остановились на',
18    homeLessonStart: 'Начать',
19    homeLessonContinue: 'Продолжить',
20    homeFirstGrammar: 'Английский алфавит и основы чтения',
21    homeFirstVocabulary: 'Светская беседа',
22    homeTopicsSectionTitle: 'Темы курса',
23    homeTopicsSectionText: 'Начните с нужного раздела. Аккаунт нужен только для сохранения прогресса и синхронизации словаря.',
24    homeEnglishGroupTitle: 'Английский',
25    homeCareerGroupTitle: 'Для работы и карьеры',
26    homeHeroSubtitle: 'Грамматика, лексика, личный тренажер слов и уроки для профессий собраны в одном понятном курсе.',
27    homeLanguageHint: 'Выберите язык интерфейса, чтобы продолжить.',
28    homeFeatureGrammar: 'Грамматика',
29    homeFeatureGrammarText: 'Короткая теория и практика',
30    homeFeatureVocabulary: 'Лексика',
31    homeFeatureVocabularyText: 'Слова, примеры и тренировки',
32    homeFeatureProgress: 'Прогресс',
33    homeFeatureProgressText: 'тест уровня и прогресс',
34    homeFeatureProfessionsText: 'Рабочие ситуации и фразы',
35    chooseLanguage: 'Выберите язык интерфейса',
36    russian: 'Русский',
37    ukrainian: 'Українська',
38    chooseMode: 'Добро пожаловать в Learn English Easily!',
39    startIntroText: 'Здесь ты найдёшь всё необходимое для уверенного английского: от основ грамматики до живой лексики. Простая теория, наглядные примеры и много практики.',
40    freeMode: 'Открыть темы курса',
41    buyFull: 'Зарегистрироваться бесплатно',
42    login: 'Войти',
43    logout: 'Выйти',
44    accountMenu: 'Аккаунт',
45    freeTitle: 'Темы курса',
46    dashboardTitle: 'Главная',
47    dashboardNav: 'Главная',
48    grammar: 'Грамматика',
49    vocabulary: 'Лексика',
50    professions: 'Английский для профессий',
51    availableLessons: 'Доступные уроки',
52    locked: 'Доступно после входа',
53    back: 'Назад',
54    continueButton: 'Продолжить',
55    startCheckout: 'Создать бесплатный аккаунт',
56    payDescription: 'Создайте бесплатный аккаунт, чтобы сохранять прогресс и личный словарь.',
57    createAccount: 'Создать аккаунт',
58    email: 'Email',
59    password: 'Пароль',
60    name: 'Имя',
61    forgotPassword: 'Забыли пароль?',
62    resetPassword: 'Восстановить пароль',
63    sendResetLink: 'Отправить письмо для восстановления',
64    loginTitle: 'Вход',
65    loginAfterPurchaseHint: 'Войдите, чтобы сохранять прогресс и синхронизировать личный словарь.',
66    forgotTitle: 'Восстановление пароля',
67    registerTitle: 'Регистрация',
68    registerDescription: 'Создайте бесплатный аккаунт, чтобы сохранять прогресс и синхронизировать личный словарь.',
69    register: 'Зарегистрироваться',
70    registerSuccess: 'Аккаунт создан. Переходим на главную...',
71    successTitle: 'Аккаунт готов',
72    cancelTitle: 'Действие отменено',
73    openCreateAccount: 'Перейти к созданию аккаунта',
74    openLogin: 'Перейти ко входу',
75    loading: 'Загрузка...',
76    paymentPending: 'Платёж ещё не подтверждён. Обновите страницу через несколько секунд.',
77    paymentAlreadyUsed: 'Аккаунт с этим email уже существует. Войдите в аккаунт.',
78    paymentCancelledText: 'Платёж не завершён.',
79    fullAccessOnly: 'Эта страница доступна после входа.',
80    loginRequiredForProgress: 'Войдите, чтобы сохранять прогресс.',
81    freeAccessHint: 'Все уроки доступны бесплатно.',
82    lessonTheory: 'Теория',
83    lessonExamples: 'Примеры',
84    lessonPractice: 'Практика',
85    lessonAuthorLabel: 'Материал подготовил',
86    submitAnswers: 'Проверить ответы',
87    score: 'Результат',
88    correctAnswers: 'Правильных ответов',
89    tryAgain: 'Пройти ещё раз',
90    yourAnswer: 'Ваш ответ',
91    correctAnswer: 'Правильный ответ',
92    hint: 'Подсказка',
93    freeCourseHome: 'Темы курса',
94    fullCourseHome: 'Темы курса',
95    errorPrefix: 'Ошибка',
96    successAccountCreated: 'Аккаунт создан.',
97    adsDisabledStatus: 'Обучение открыто бесплатно',
98    purchaseActivatedNoAds: 'Аккаунт активирован.',
99    noAdsActivationAfterPurchase: 'Создайте бесплатный аккаунт, чтобы сохранять прогресс.',
100    resetEmailSent: 'Если аккаунт существует, письмо со ссылкой уже отправлено.',
101    resetEmailSentReal: 'Письмо для восстановления пароля отправлено на ваш email.',
102    enterEmail: 'Введите email',
103    confirmPassword: 'Повторите пароль',
104    saveNewPassword: 'Сохранить новый пароль',
105    passwordsDoNotMatch: 'Пароли не совпадают.',
106    passwordResetSuccess: 'Пароль успешно изменён. Переходим ко входу...',
107    resetLinkInvalid: 'Ссылка для сброса недействительна или устарела.',
108    signInError: 'Не удалось войти. Проверьте email и пароль.',
109    checkoutError: 'Не удалось открыть регистрацию',
110    creatingInvoice: 'Открываем регистрацию...',
111    openGrammar: 'Открыть грамматику',
112    openVocabulary: 'Открыть лексику',
113    openProfessions: 'Открыть уроки',
114    previewProfessions: 'Открыть уроки',
115    lessonLockedTitle: 'Урок доступен',
116    lessonLockedText: 'Все уроки доступны бесплатно.',
117    accountExists: 'Аккаунт с таким email уже существует. Используйте вход.',
118    passwordMin: 'Минимальная длина пароля — 8 символов.',
119    passwordMinReset: 'Минимальная длина пароля — 8 символов.',
120    noLesson: 'Урок не найден.',
121    welcomeFree: 'Все уроки доступны бесплатно.',
122    welcomeFull: 'Ваш прогресс и личный словарь сохраняются в аккаунте.',
123    returnHome: 'На главную',
124    returnStart: 'К выбору режима',
125    close: 'Закрыть',
126    myVocabularyTrainer: 'Мой тренажер слов',
127    openTrainer: 'Открыть тренажер',
128    placementTestBadge: 'Тест уровня',
129    placementTestCardTitle: 'Хотите проверить свой уровень?',
130    placementTestCardText: 'Ответьте на вопросы и получите подсказку, с какого места начать курс.',
131    openPlacementTest: 'Пройти тест',
132    resumeBuilderBadge: 'Создать резюме',
133    resumeBuilderCardTitle: 'Создай резюме, которое заметят',
134    resumeBuilderCardText: '36 готовых шаблонов: выберите стиль, заполните данные, настройте цвет и скачайте PDF.',
135    resumeBuilderCardTextShort: '36 готовых шаблонов: выберите стиль, заполните данные и скачайте PDF.',
136    openResumeBuilder: 'Открыть шаблоны',
137    qaPracticumBadge: 'QA / SDET Практикум',
138    qaPracticumCardText: 'Теория, практика, вопросы для собеседований и чек-листы.',
139    qaPracticumMeta: '20 модулей · 643 урока',
140    placementTestPageTitle: 'Проверка уровня английского',
141    placementTestPageSubtitle: 'Одна страница с вопросами по грамматике, лексике, чтению и живым ситуациям.',
142    placementTestHeading: 'Проверьте свой английский перед стартом',
143    placementTestIntro: 'Выберите ответы на все вопросы. После проверки вы увидите результат, рекомендации и полный разбор.',
144    trainerSectionDescription: 'Добавляйте свои слова, собирайте личный словарь и тренируйте лексику в отдельных режимах.',
145    trainerSectionDescriptionShort: 'Личный словарь, категории и 9 вариантов тренировок.',
146    trainerDictionarySubtitle: 'Слова хранятся отдельно от уроков и не влияют на структуру курса.',
147    addWord: 'Добавить слово',
148    editWord: 'Редактировать слово',
149    deleteWord: 'Удалить слово',
150    word: 'Слово',
151    wordOrPhrase: 'Слово или фраза',
152    translation: 'Перевод',
153    category: 'Категория',
154    generalCategory: 'Общая',
155    trainerNewCategory: '+ Новая категория',
156    trainerNewCategoryName: 'Название новой категории',
157    trainerNewCategoryPlaceholder: 'Например, Путешествия',
158    trainerNewCategoryHint: 'Категория появится в списке после сохранения слова.',
159    trainerChooseExistingCategory: 'Выбрать существующую',
160    trainerCategoryRequiredError: 'Введите название категории.',
161    training: 'Тренировка',
162    multipleChoice: 'Выбор ответа',
163    flashcards: 'Карточки',
164    buildWord: 'Собрать слово',
165    trainerTyping: 'Напиши на английском',
166    trainerTypingDescription: 'Прочитайте перевод и введите английское слово или фразу самостоятельно.',
167    trainerListening: 'Услышал → написал',
168    trainerListeningDescription: 'Прослушайте английское слово или фразу и напишите услышанное.',
169    trainerBuildPhrase: 'Собрать фразу',
170    trainerBuildPhraseDescription: 'Соберите английскую фразу из перемешанных слов по её переводу.',
171    trainerNeedPhrase: 'Нужна хотя бы одна фраза из двух и более слов в тренировке.',
172    trainerBlitz: 'Блиц · 60 секунд',
173    trainerBlitzDescription: 'За 60 секунд выберите как можно больше правильных переводов.',
174    trainerBlitzHint: 'Нажмите вариант — ответ проверится сразу. Следующий вопрос появится автоматически.',
175    trainerBlitzFinished: 'Время вышло! Вот ваш результат за 60 секунд.',
176    trainerMistakes: 'Ошибки',
177    trainerAnswersGiven: 'Всего ответов',
178    trainerTimeLeft: 'Осталось времени',
179    trainerPaused: 'Пауза',
180    trainerListenPrompt: 'Прослушайте и напишите по-английски',
181    trainerListenAgain: 'Прослушать',
182    trainerTypeEnglish: 'Ваш ответ на английском',
183    trainerDontRemember: 'Не помню',
184    trainerTapWordsHint: 'Нажимайте на слова в правильном порядке',
185    trainerRemoveWord: 'Убрать слово',
186    showAnswer: 'Показать ответ',
187    knowWord: 'Знаю',
188    dontKnowWord: 'Не знаю',
189    save: 'Сохранить',
190    cancel: 'Отмена',
191    savedToTrainer: 'Сохранено в тренажер слов',
192    addWordToTrainer: 'Добавить слово в тренажер',
193    trainerGuestBannerTitle: 'Войдите, чтобы синхронизировать словарь',
194    trainerGuestBannerText: 'Сейчас ваши слова сохраняются только в этом браузере. Бесплатный аккаунт сохранит словарь и прогресс.',
195    trainerTotalWords: 'Всего слов',
196    trainerTrainingWords: 'В тренировке',
197    trainerWordsInTraining: 'Слов в тренировке',
198    trainerSearchPlaceholder: 'Поиск по слову, переводу или категории',
199    trainerNothingFound: 'Ничего не найдено.',
200    trainerEmptyDictionary: 'Словарь пока пуст. Добавьте первое слово.',
201    trainingEnabled: 'В тренировке',
202    trainingDisabled: 'Вне тренировки',
203    addToTraining: 'Добавить в тренировку',
204    removeFromTraining: 'Убрать из тренировки',
205    allCategories: 'Все категории',
206    trainingCategory: 'Категория тренировки',
207    trainerTrainingSubtitle: 'Выберите категорию и режим, который хотите пройти.',
208    trainerChooseModeTitle: 'Как потренируемся?',
209    trainerChooseModeSubtitle: 'Вспоминайте, пишите, слушайте — выберите свой способ учить слова.',
210    trainerChooseTranslation: 'Выбрать перевод',
211    trainerChooseWord: 'Выбрать слово',
212    trainerRecallTranslation: 'Вспомнить перевод',
213    trainerRecallWord: 'Вспомнить слово',
214    trainerSpellingSkill: 'Из букв',
215    trainerWritingSkill: 'Письмо',
216    trainerListeningSkill: 'На слух',
217    trainerWordOrderSkill: 'Порядок слов',
218    trainerSpeedSkill: 'На скорость',
219    trainerStartMode: 'Начать',
220    trainerWordCountLabel: 'Слов:',
221    trainerPhraseCountLabel: 'Фраз:',
222    trainerAddPhraseToStart: 'Нужна фраза',
223    trainerTwoWordsToStart: 'Нужно 2 слова',
224    trainerOneWordToStart: 'Нужно слово',
225    trainerNoAudio: 'Нет озвучки',
226    trainerMultipleChoiceWordToTranslationDescription: 'Показывается английское слово, нужно выбрать правильный перевод.',
227    trainerMultipleChoiceTranslationToWordDescription: 'Показывается перевод, нужно выбрать правильное английское слово.',
228    trainerFlashcardsWordToTranslationDescription: 'Сначала видите английское слово, затем открываете перевод.',
229    trainerFlashcardsTranslationToWordDescription: 'Сначала видите перевод, затем открываете английское слово.',
230    trainerBuildWordDescription: 'По переводу соберите английское слово или фразу из букв и пробелов.',
231    trainerChooseCorrectAnswer: 'Выберите правильный ответ',
232    trainerAnswerCorrect: 'Правильно',
233    trainerAnswerIncorrect: 'Неправильно',
234    trainerCheckAnswer: 'Проверить',
235    trainerNextWord: 'Следующее слово',
236    trainerTapLettersHint: 'Нажимайте на буквы и пробелы, чтобы собрать ответ',
237    trainerSpace: 'Пробел',
238    trainerDeleteLetter: 'Удалить букву',
239    trainerClearAnswer: 'Очистить',
240    trainerSpeakEnglish: 'Прослушать английское слово',
241    trainerSpeechUnavailable: 'Озвучка недоступна в этом браузере.',
242    trainerNeedAtLeastTwoWords: 'Для этого режима нужно минимум 2 слова в тренировке.',
243    trainerNeedAtLeastOneWord: 'Для этого режима нужно хотя бы 1 слово в тренировке.',
244    trainerDeleteConfirm: 'Удалить "{word}" из словаря?',
245    knownWords: 'Знаю',
246    unknownWords: 'Не знаю',
247    trainerWordRequiredError: 'Введите слово.',
248    trainerTranslationRequiredError: 'Введите перевод.',
249    trainerWordNotFoundError: 'Слово не найдено.',
250    trainerInvalidPayloadError: 'Некорректные данные слова.',
251    trainerSyncInvalidPayloadError: 'Некорректные данные для синхронизации.',
252
253    registerLockedDescription: 'Регистрация бесплатная.',
254    registerLockedNotice: 'Создайте аккаунт, чтобы сохранять прогресс и словарь.',
255    alreadyHaveAccountLogin: 'Уже есть аккаунт — Войти',
256    paidRegistrationDescription: 'Укажите email и пароль, чтобы создать бесплатный аккаунт.',
257    registerOnlyAfterPayment: 'Регистрация бесплатная. Заполните форму.',
258
259    contactTitle: 'У нас также есть приложение',
260    contactText: 'Вы можете учиться в веб-версии или установить приложение из Google Play.',
261    contactLinkText: 'Перейти в Google Play',
262
263    fullBadge: 'Бесплатно',
264    professionsPaidOnly: 'Все уроки для работы и профессий доступны бесплатно.',
265    feedbackButton: 'Связаться',
266    feedbackTitle: 'Связаться со мной',
267    feedbackText: 'Заметили ошибку, есть идея для нового урока или хотите что-то предложить? Напишите мне — я читаю все сообщения и постепенно улучшаю сайт.',
268    feedbackEmailLabel: 'Почта поддержки',
269    feedbackLinkedInLabel: 'LinkedIn',
270    feedbackLinkedInText: 'Перейти на страницу автора',
271    footerAbout: 'О проекте',
272    footerContact: 'Контакты',
273    footerWebsitePrivacy: 'Конфиденциальность сайта',
274    footerAndroidPrivacy: 'Политика Android',
275    footerTerms: 'Условия использования',
276    availableNow: 'Доступен',
277    copyEmail: 'Скопировать',
278    copiedEmail: 'Скопировано',
279    feedbackCopySuccess: 'Почта скопирована в буфер обмена.',
280    feedbackCopyFailed: 'Не удалось скопировать почту. Скопируйте адрес вручную.',
281    completed: 'Пройдено',
282    notCompleted: 'Не пройдено',
283    open: 'Открыть',
284    buy: 'Зарегистрироваться бесплатно',
285    resultShownButNotSaved: 'Результат показан, но прогресс не сохранился',
286
287    markLessonCompleted: 'Отметить урок как пройденный',
288    typeAnswer: 'Введите ответ',
289    notAnswered: '—',
290    taskSingleChoice: 'Выбор ответа',
291    taskGapChoice: 'Заполните пропуск',
292    taskTranslationChoice: 'Перевод',
293    taskDialogueChoice: 'Диалог',
294    taskSentenceChoice: 'Предложение',
295    taskMatchChoice: 'Сопоставление',
296
297    invalidEmail: 'Укажите корректный email',
298    userNotFound: 'Пользователь с таким email не найден',
299    resetLinkCreateError: 'Не удалось создать ссылку для восстановления',
300    resetEmailSendError: 'Не удалось отправить письмо. Проверьте почтовый ящик домена и настройки mail() на хостинге.',
301    tokenMissing: 'Отсутствует token',
302    resetLinkUsed: 'Ссылка уже использована',
303    resetLinkExpired: 'Срок действия ссылки истёк',
304    passwordMin8: 'Пароль должен содержать минимум 8 символов',
305    passwordUpdated: 'Пароль успешно обновлён',
306    emailAndPasswordRequired: 'Email и пароль обязательны',
307    invalidCredentials: 'Неверный email или пароль',
308    registrationOnlyAfterPayment: 'Регистрация доступна бесплатно',
309    invalidEmailGeneric: 'Некорректный email',
310    paymentSessionNotConfirmed: 'Сессия регистрации не подтверждена. Попробуйте ещё раз.',
311    paymentAlreadyUsedRegister: 'Этот платёж уже был использован для регистрации',
312    paymentConfirmFailed: 'Не удалось подтвердить действие',
313    paymentNotConfirmed: 'Действие не подтверждено',
314    invalidPaymentId: 'Некорректный идентификатор платежа',
315    accountCreateError: 'Не удалось создать аккаунт',
316
317    resetEmailSubject: 'Курс английского языка — восстановление пароля',
318    resetEmailHello: 'Здравствуйте!',
319    resetEmailRequest: 'Мы получили запрос на восстановление пароля для аккаунта',
320    resetEmailAction: 'Нажмите здесь, чтобы установить новый пароль',
321    resetEmailExpires: 'Ссылка действительна',
322    resetEmailMinutes: 'минут',
323    resetEmailIgnore: 'Если это были не вы, просто проигнорируйте это письмо.',
324    resetEmailTextAction: 'Откройте ссылку, чтобы установить новый пароль:'
325  },
326
327  ua: {
328    siteTitle: 'Курс англійської мови',
329    homeSiteTitle: 'Learn English Easily — вивчайте англійську крок за кроком',
330    homeEyebrow: 'Уроки та розмовна практика',
331    homeTopicsTitle: 'Англійська крок за кроком',
332    homeTopicsTitleLead: 'Англійська',
333    homeTopicsTitleLine2: 'крок за кроком',
334    homeTopicsSubtitle: 'Розбирайтеся в граматиці, вивчайте нові слова й тренуйте розмовне мовлення. Оберіть тему та почніть навчатися безкоштовно.',
335    homeLearningStart: 'Почніть із першого уроку',
336    homeLearningContinue: 'Продовжте, де зупинилися',
337    homeLearningStartNote: 'Можна почати без реєстрації',
338    homeLearningContinueNote: 'Останні відкриті уроки в цьому браузері',
339    homeLessonFirst: 'Перший урок',
340    homeLessonRecent: 'Ви зупинилися на',
341    homeLessonStart: 'Почати',
342    homeLessonContinue: 'Продовжити',
343    homeFirstGrammar: 'Англійський алфавіт та основи читання',
344    homeFirstVocabulary: 'Світська бесіда',
345    homeTopicsSectionTitle: 'Теми курсу',
346    homeTopicsSectionText: 'Почніть із потрібного розділу. Акаунт потрібен лише для збереження прогресу та синхронізації словника.',
347    homeEnglishGroupTitle: 'Англійська',
348    homeCareerGroupTitle: 'Для роботи та кар’єри',
349    homeHeroSubtitle: 'Граматика, лексика, особистий тренажер слів і уроки для професій зібрані в одному зрозумілому курсі.',
350    homeLanguageHint: 'Оберіть мову інтерфейсу, щоб продовжити.',
351    homeFeatureGrammar: 'Граматика',
352    homeFeatureGrammarText: 'Коротка теорія і практика',
353    homeFeatureVocabulary: 'Лексика',
354    homeFeatureVocabularyText: 'Слова, приклади і тренування',
355    homeFeatureProgress: 'Прогрес',
356    homeFeatureProgressText: 'тест рівня і прогрес',
357    homeFeatureProfessionsText: 'Робочі ситуації та фрази',
358    chooseLanguage: 'Оберіть мову інтерфейсу',
359    russian: 'Російська',
360    ukrainian: 'Українська',
361    chooseMode: 'Ласкаво просимо до Learn English Easily!',
362    startIntroText: 'Тут ти знайдеш усе необхідне для впевненої англійської: від основ граматики до живої лексики. Проста теорія, наочні приклади та багато практики.',
363    freeMode: 'Відкрити теми курсу',
364    buyFull: 'Зареєструватися безкоштовно',
365    login: 'Увійти',
366    logout: 'Вийти',
367    accountMenu: 'Акаунт',
368    freeTitle: 'Теми курсу',
369    dashboardTitle: 'Головна',
370    dashboardNav: 'Головна',
371    grammar: 'Граматика',
372    vocabulary: 'Лексика',
373    professions: 'Англійська для професій',
374    availableLessons: 'Доступні уроки',
375    locked: 'Доступно після входу',
376    back: 'Назад',
377    continueButton: 'Продовжити',
378    startCheckout: 'Створити безкоштовний акаунт',
379    payDescription: 'Створіть безкоштовний акаунт, щоб зберігати прогрес і особистий словник.',
380    createAccount: 'Створити акаунт',
381    email: 'Email',
382    password: 'Пароль',
383    name: "Ім'я",
384    forgotPassword: 'Забули пароль?',
385    resetPassword: 'Відновити пароль',
386    sendResetLink: 'Надіслати лист для відновлення',
387    loginTitle: 'Вхід',
388    loginAfterPurchaseHint: 'Увійдіть, щоб зберігати прогрес і синхронізувати особистий словник.',
389    forgotTitle: 'Відновлення пароля',
390    registerTitle: 'Реєстрація',
391    registerDescription: 'Створіть безкоштовний акаунт, щоб зберігати прогрес і синхронізувати особистий словник.',
392    register: 'Зареєструватися',
393    registerSuccess: 'Акаунт створено. Переходимо на головну...',
394    successTitle: 'Акаунт готовий',
395    cancelTitle: 'Дію скасовано',
396    openCreateAccount: 'Перейти до створення акаунта',
397    openLogin: 'Перейти до входу',
398    loading: 'Завантаження...',
399    paymentPending: 'Платіж ще не підтверджено. Оновіть сторінку за кілька секунд.',
400    paymentAlreadyUsed: 'Акаунт з цим email уже існує. УвÑ
400–йдіть в акаунт.',
401    paymentCancelledText: 'Платіж не завершено.',
402    fullAccessOnly: 'Ця сторінка доступна після входу.',
403    loginRequiredForProgress: 'Увійдіть, щоб зберігати прогрес.',
404    freeAccessHint: 'Усі уроки доступні безкоштовно.',
405    lessonTheory: 'Теорія',
406    lessonExamples: 'Приклади',
407    lessonPractice: 'Практика',
408    lessonAuthorLabel: 'Матеріал підготував',
409    submitAnswers: 'Перевірити відповіді',
410    score: 'Результат',
411    correctAnswers: 'Правильних відповідей',
412    tryAgain: 'Пройти ще раз',
413    yourAnswer: 'Ваша відповідь',
414    correctAnswer: 'Правильна відповідь',
415    hint: 'Підказка',
416    freeCourseHome: 'Теми курсу',
417    fullCourseHome: 'Теми курсу',
418    errorPrefix: 'Помилка',
419    successAccountCreated: 'Акаунт створено.',
420    adsDisabledStatus: 'Навчання відкрите безкоштовно',
421    purchaseActivatedNoAds: 'Акаунт активовано.',
422    noAdsActivationAfterPurchase: 'Створіть безкоштовний акаунт, щоб зберігати прогрес.',
423    resetEmailSent: 'Якщо акаунт існує, лист із посиланням уже надіслано.',
424    resetEmailSentReal: 'Лист для відновлення пароля надіслано на ваш email.',
425    enterEmail: 'Введіть email',
426    confirmPassword: 'Повторіть пароль',
427    saveNewPassword: 'Зберегти новий пароль',
428    passwordsDoNotMatch: 'Паролі не збігаються.',
429    passwordResetSuccess: 'Пароль успішно змінено. Переходимо до входу...',
430    resetLinkInvalid: 'Посилання для скидання недійсне або застаріло.',
431    signInError: 'Не вдалося увійти. Перевірте email і пароль.',
432    checkoutError: 'Не вдалося відкрити реєстрацію',
433    creatingInvoice: 'Відкриваємо реєстрацію...',
434    openGrammar: 'Відкрити граматику',
435    openVocabulary: 'Відкрити лексику',
436    openProfessions: 'Відкрити уроки',
437    previewProfessions: 'Відкрити уроки',
438    lessonLockedTitle: 'Урок доступний',
439    lessonLockedText: 'Усі уроки доступні безкоштовно.',
440    accountExists: 'Акаунт з таким email уже існує. Використайте вхід.',
441    passwordMin: 'Мінімальна довжина пароля — 8 символів.',
442    passwordMinReset: 'Мінімальна довжина пароля — 8 символів.',
443    noLesson: 'Урок не знайдено.',
444    welcomeFree: 'Усі уроки доступні безкоштовно.',
445    welcomeFull: 'Ваш прогрес і особистий словник зберігаються в акаунті.',
446    returnHome: 'На головну',
447    returnStart: 'До вибору режиму',
448    close: 'Закрити',
449    myVocabularyTrainer: 'Мій тренажер слів',
450    openTrainer: 'Відкрити тренажер',
451    placementTestBadge: 'Тест рівня',
452    placementTestCardTitle: 'Хочете перевірити свій рівень?',
453    placementTestCardText: 'Дайте відповіді на питання й отримайте підказку, з якого місця починати Ð
453ºÑƒÑ€Ñ.',
454    openPlacementTest: 'Пройти тест',
455    resumeBuilderBadge: 'Створити резюме',
456    resumeBuilderCardTitle: 'Створи резюме, яке помітять',
457    resumeBuilderCardText: '36 готових шаблонів: оберіть стиль, заповніть дані, налаштуйте колір і завантажте PDF.',
458    resumeBuilderCardTextShort: '36 готових шаблонів: оберіть стиль, заповніть дані та завантажте PDF.',
459    openResumeBuilder: 'Відкрити шаблони',
460    qaPracticumBadge: 'QA / SDET Практикум',
461    qaPracticumCardText: 'Теорія, практика, питання для співбесід і чеклісти.',
462    qaPracticumMeta: '20 модулів · 643 уроки',
463    placementTestPageTitle: 'Перевірка рівня англійської',
464    placementTestPageSubtitle: 'Одна сторінка з питаннями з граматики, лексики, читання та живих ситуацій.',
465    placementTestHeading: 'Перевірте свою англійську перед стартом',
466    placementTestIntro: 'Оберіть відповіді на всі питання. Після перевірки ви побачите результат, рекомендації та повний розбір.',
467    trainerSectionDescription: 'Додавайте свої слова, збирайте особистий словник і тренуйте лексику в окремих режимах.',
468    trainerSectionDescriptionShort: 'Особистий словник, категорії та 9 варіантів тренувань.',
469    trainerDictionarySubtitle: 'Слова зберігаються окремо від уроків і не впливають на структуру курсу.',
470    addWord: 'Додати слово',
471    editWord: 'Редагувати слово',
472    deleteWord: 'Видалити слово',
473    word: 'Слово',
474    wordOrPhrase: 'Слово або фраза',
475    translation: 'Переклад',
476    category: 'Категорія',
477    generalCategory: 'Загальна',
478    trainerNewCategory: '+ Нова категорія',
479    trainerNewCategoryName: 'Назва нової категорії',
480    trainerNewCategoryPlaceholder: 'Наприклад, Подорожі',
481    trainerNewCategoryHint: 'Категорія з’явиться у списку після збереження слова.',
482    trainerChooseExistingCategory: 'Вибрати наявну',
483    trainerCategoryRequiredError: 'Введіть назву категорії.',
484    training: 'Тренування',
485    multipleChoice: 'Вибір відповіді',
486    flashcards: 'Картки',
487    buildWord: 'Скласти слово',
488    trainerTyping: 'Напиши англійською',
489    trainerTypingDescription: 'Прочитайте переклад і введіть англійське слово або фразу самостійно.',
490    trainerListening: 'Почув → написав',
491    trainerListeningDescription: 'Прослухайте англійське слово або фразу та напишіть почуте.',
492    trainerBuildPhrase: 'Скласти фразу',
493    trainerBuildPhraseDescription: 'Складіть англійську Ñ
493„разу з перемішаних слів за її перекладом.',
494    trainerNeedPhrase: 'Потрібна хоча б одна фраза з двох і більше слів у тренуванні.',
495    trainerBlitz: 'Бліц · 60 секунд',
496    trainerBlitzDescription: 'За 60 секунд оберіть якомога більше правильних перекладів.',
497    trainerBlitzHint: 'Натисніть варіант — відповідь перевіриться одразу. Наступне запитання з’явиться автоматично.',
498    trainerBlitzFinished: 'Час вийшов! Ось ваш результат за 60 секунд.',
499    trainerMistakes: 'Помилки',
500    trainerAnswersGiven: 'Усього відповідей',
501    trainerTimeLeft: 'Залишилося часу',
502    trainerPaused: 'Пауза',
503    trainerListenPrompt: 'Прослухайте та напишіть англійською',
504    trainerListenAgain: 'Прослухати',
505    trainerTypeEnglish: 'Ваша відповідь англійською',
506    trainerDontRemember: 'Не пам’ятаю',
507    trainerTapWordsHint: 'Натискайте на слова у правильному порядку',
508    trainerRemoveWord: 'Прибрати слово',
509    showAnswer: 'Показати відповідь',
510    knowWord: 'Знаю',
511    dontKnowWord: 'Не знаю',
512    save: 'Зберегти',
513    cancel: 'Скасувати',
514    savedToTrainer: 'Збережено в тренажер слів',
515    addWordToTrainer: 'Додати слово в тренажер',
516    trainerGuestBannerTitle: 'Увійдіть, щоб синхронізувати словник',
517    trainerGuestBannerText: 'Зараз ваші слова зберігаються лише в цьому браузері. Безкоштовний акаунт збереже словник і прогрес.',
518    trainerTotalWords: 'Усього слів',
519    trainerTrainingWords: 'У тренуванні',
520    trainerWordsInTraining: 'Слів у тренуванні',
521    trainerSearchPlaceholder: 'Пошук за словом, перекладом або категорією',
522    trainerNothingFound: 'Нічого не знайдено.',
523    trainerEmptyDictionary: 'Словник поки порожній. Додайте перше слово.',
524    trainingEnabled: 'У тренуванні',
525    trainingDisabled: 'Поза тренуванням',
526    addToTraining: 'Додати в тренування',
527    removeFromTraining: 'Прибрати з тренування',
528    allCategories: 'Усі категорії',
529    trainingCategory: 'Категорія тренування',
530    trainerTrainingSubtitle: 'Оберіть категорію та режим, який хочете пройти.',
531    trainerChooseModeTitle: 'Як потренуємося?',
532    trainerChooseModeSubtitle: 'Пригадуйте, пишіть, слухайте — оберіть свій спосіб вивчати слова.',
533    trainerChooseTranslation: 'Вибрати переклад',
534    trainerChooseWord: 'Вибрати слово',
535    trainerRecallTranslation: 'Пригадати переклад',
536    trainerRecallWord: 'Пригадати слово',
537    trainerSpellingSkill: 'Із літер',
538    trainerWritingSkill: 'Письмо',
539    trainerListeningSkill: 'На слух',
540    trainerWordOrderSkill: 'Порядок слів',
541    trainerSpeedSkill: 'На швидкість',
542    trainerStartMode: 'Почати',
543    trainerWordCountLabel: 'Слів:',
544    trainerPhraseCountLabel: 'Фраз:',
545    trainerAddPhraseToStart: 'Потрібна фраза',
546    trainerTwoWordsToStart: 'Потрібно 2 слова',
547    trainerOneWordToStart: 'Потрібне слово',
548    trainerNoAudio: 'Немає озвучення',
549    trainerMultipleChoiceWordToTranslationDescription: 'Показується англійське слово, потрібно вибрати правильний переклад.',
550    trainerMultipleChoiceTranslationToWordDescription: 'Показується переклад, потрібно вибрати правильне англійське слово.',
551    trainerFlashcardsWordToTranslationDescription: 'Спочатку бачите англійське слово, потім відкриваєте переклад.',
552    trainerFlashcardsTranslationToWordDescription: 'Спочатку бачите переклад, потім відкриваєте англійське слово.',
553    trainerBuildWordDescription: 'За перекладом складіть англійське слово або фразу з л
553ітер і пробілів.',
554    trainerChooseCorrectAnswer: 'Оберіть правильну відповідь',
555    trainerAnswerCorrect: 'Правильно',
556    trainerAnswerIncorrect: 'Неправильно',
557    trainerCheckAnswer: 'Перевірити',
558    trainerNextWord: 'Наступне слово',
559    trainerTapLettersHint: 'Натискайте на літери та пробіли, щоб скласти відповідь',
560    trainerSpace: 'Пробіл',
561    trainerDeleteLetter: 'Видалити літеру',
562    trainerClearAnswer: 'Очистити',
563    trainerSpeakEnglish: 'Прослухати англійське слово',
564    trainerSpeechUnavailable: 'Озвучка недоступна в цьому браузері.',
565    trainerNeedAtLeastTwoWords: 'Для цього режиму потрібно мінімум 2 слова в тренуванні.',
566    trainerNeedAtLeastOneWord: 'Для цього режиму потрібне щонайменше 1 слово в тренуванні.',
567    trainerDeleteConfirm: 'Видалити "{word}" зі словника?',
568    knownWords: 'Знаю',
569    unknownWords: 'Не знаю',
570    trainerWordRequiredError: 'Введіть слово.',
571    trainerTranslationRequiredError: 'Введіть переклад.',
572    trainerWordNotFoundError: 'Слово не знайдено.',
573    trainerInvalidPayloadError: 'Некоректні дані слова.',
574    trainerSyncInvalidPayloadError: 'Некоректні дані для синхронізації.',
575
576    registerLockedDescription: 'Реєстрація безкоштовна.',
577    registerLockedNotice: 'Створіть акаунт, щоб зберігати прогрес і словник.',
578    alreadyHaveAccountLogin: 'Вже є акаунт — Увійти',
579    paidRegistrationDescription: 'Вкажіть email і пароль, щоб створити безкоштовний акаунт.',
580    registerOnlyAfterPayment: 'Реєстрація безкоштовна. Заповніть форму.',
581
582    contactTitle: 'У нас також є застосунок',
583    contactText: 'Ви можете навчатися у веб-версії або встановити застосунок з Google Play.',
584    contactLinkText: 'Перейти в Google Play',
585
586    fullBadge: 'Безкоштовно',
587    professionsPaidOnly: 'Усі уроки для роботи та професій доступні безкоштовно.',
588    feedbackButton: "Зв'язатися",
589    feedbackTitle: 'Зв’язатися зі мною',
590    feedbackText: 'Помітили помилку, маєте ідею для нового уроку або хочете щось запропонувати? Напишіть мені — я читаю всі повідомлення й поступово покращую сайт.',
591    feedbackEmailLabel: 'Пошта підтримки',
592    feedbackLinkedInLabel: 'LinkedIn',
593    feedbackLinkedInText: 'Перейти на сторінку автора',
594    footerAbout: 'Про проєкт',
595    footerContact: 'Контакти',
596    footerWebsitePrivacy: 'Конфіденційність сайту',
597    footerAndroidPrivacy: 'Політика Android',
598    footerTerms: 'Умови використання',
599    availableNow: 'Доступний',
600    copyEmail: 'Скопіювати',
601    copiedEmail: 'Скопійовано',
602    feedbackCopySuccess: 'Пошту скопійовано до буфера обміну.',
603    feedbackCopyFailed: 'Не вдалося скопіювати пошту. Скопіюйте адресу вручну.',
604    completed: 'Пройдено',
605    notCompleted: 'Не пройдено',
606    open: 'Відкрити',
607    buy: 'Зареєструватися безкоштовно',
608    resultShownButNotSaved: 'Результат показано, але прогрес не збережено',
609
610    markLessonCompleted: 'Позначити урок як пройдений',
611    typeAnswer: 'Введіть відповідь',
612    notAnswered: '—',
613    taskSingleChoice: 'Вибір відповіді',
614    taskGapChoice: 'Заповніть пропуск',
615    taskTranslationChoice: 'Переклад',
616    taskDialogueChoice: 'Діалог',
617    taskSentenceChoice: 'Речення',
618    taskMatchChoice: 'Зіставлення',
619
620    invalidEmail: 'Вкажіть коректний email',
621    userNotFound: 'Користувача з таким email не знайдено',
622    resetLinkCreateError: 'Не вдалося створити посилання для відновлення',
623    resetEmailSendError: 'Не вдалося надіслати лист. Перевірте поштову скриньку домену та налаштування mail() на хостингу.',
624    tokenMissing: 'Відсутній token',
625    resetLinkUsed: 'Посилання вже використано',
626    resetLinkExpired: 'Термін дії посилання минув',
627    passwordMin8: 'Пароль має містити щонайменше 8 символів',
628    passwordUpdated: 'Пароль успішно оновлено',
629    emailAndPasswordRequired: "Email і пароль обов'язкові",
630    invalidCredentials: 'Неправильний email або пароль',
631    registrationOnlyAfterPayment: 'Реєстрація доступна безкоштовно',
632    invalidEmailGeneric: 'Некоректний email',
633    paymentSessionNotConfirmed: 'Сесію реєстрації не підтверджено. Спробуйте ще раз.',
634    paymentAlreadyUsedRegister: 'Цей платіж уже був використаний для реєстрації',
635    paymentConfirmFailed: 'Не вдалося підтвердити дію',
636    paymentNotConfirmed: 'Дію не підтверджено',
637    invalidPaymentId: 'Некоректний ідентифікатор платежу',
638    accountCreateError: 'Не вдалося створити акаунт',
639
640    resetEmailSubject: 'Курс англійської мови — відновлення пароля',
641    resetEmailHello: 'Вітаємо!',
642    resetEmailRequest: 'Ми отримали запит на відновлення пароля для акаунта',
643    resetEmailAction: 'Натисніть тут, щоб встановити новий пароль',
644    resetEmailExpires: 'Посилання дійсне',
645    resetEmailMinutes: 'хвилин',
646    resetEmailIgnore: 'Якщо це були не ви, просто проігноруйте цей лист.',
647    resetEmailTextAction: 'Відкрийте посилання, щоб встановити новий пароль:'
648  }
649};
650
651export function t(key, lang = getLanguage()) {
652  return messages[lang]?.[key] || messages.ru[key] || key;
653}
654
655export function applyTranslations(lang = getLanguage()) {
656  document.documentElement.lang = lang === 'ua' ? 'uk' : 'ru';
657
658  document.querySelectorAll('[data-i18n]').forEach((node) => {
659    node.textContent = t(node.dataset.i18n, lang);
660  });
661
662  document.querySelectorAll('[data-i18n-placeholder]').forEach((node) => {
663    node.placeholder = t(node.dataset.i18nPlaceholder, lang);
664  });
665
666}
667
668export function setAndApplyLanguage(lang) {
669  setLanguage(lang);
670  applyTranslations(lang);
671}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.