HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>После прохождения курса<a>JS: Архитектура фронтенда</a>я решил вернуться к упражнению по организации текстов интерфейса и доработать его так, чтобы создавать массив с названием добавленных языков не требовалось, а данные автоматически загружались из файловой системы.</p>
1 <p>После прохождения курса<a>JS: Архитектура фронтенда</a>я решил вернуться к упражнению по организации текстов интерфейса и доработать его так, чтобы создавать массив с названием добавленных языков не требовалось, а данные автоматически загружались из файловой системы.</p>
2 <h2>Как перенести упражнение на компьютер</h2>
2 <h2>Как перенести упражнение на компьютер</h2>
3 <p>Кажется, что сделать это легко - достаточно скопировать код и установить нужные библиотеки. Но, к сожалению, реальность полна разочарований.</p>
3 <p>Кажется, что сделать это легко - достаточно скопировать код и установить нужные библиотеки. Но, к сожалению, реальность полна разочарований.</p>
4 <h3>Webpack</h3>
4 <h3>Webpack</h3>
5 <p>Обязательная библиотека в этом проекте -<a>Webpack</a>. Благодаря ей вы не будете ограничены функцией импорта модулей. Кроме того, вам не придется подключать десятки скриптов к HTML-странице. Webpack соберет весь код в один файл и упростит подключение других библиотек. Для установки Webpack можно воспользоваться<a>этой инструкцией</a>.</p>
5 <p>Обязательная библиотека в этом проекте -<a>Webpack</a>. Благодаря ей вы не будете ограничены функцией импорта модулей. Кроме того, вам не придется подключать десятки скриптов к HTML-странице. Webpack соберет весь код в один файл и упростит подключение других библиотек. Для установки Webpack можно воспользоваться<a>этой инструкцией</a>.</p>
6 <p>После настройки Webpack можно просто скопировать код, устанавливать нужные библиотеки и начинать экспериментировать.</p>
6 <p>После настройки Webpack можно просто скопировать код, устанавливать нужные библиотеки и начинать экспериментировать.</p>
7 <h2>Приступаю к проекту</h2>
7 <h2>Приступаю к проекту</h2>
8 <p>Первым делом я перенёс верстку в отдельный HTML-файл и подключил Bootstrap к JS-файлу. затем переписал код так, чтобы он соответствовал модели MVC (или моему ложному пониманию данной модели). Вынес модель в отдельный файл с инициализацией, который запускается только один раз и в котором создается новый инстанс i18next.</p>
8 <p>Первым делом я перенёс верстку в отдельный HTML-файл и подключил Bootstrap к JS-файлу. затем переписал код так, чтобы он соответствовал модели MVC (или моему ложному пониманию данной модели). Вынес модель в отдельный файл с инициализацией, который запускается только один раз и в котором создается новый инстанс i18next.</p>
9 <p>Затем перенес все функции рендера в файл view.js, а все контроллеры - в app.js.</p>
9 <p>Затем перенес все функции рендера в файл view.js, а все контроллеры - в app.js.</p>
10 <h2>Ложный путь</h2>
10 <h2>Ложный путь</h2>
11 <p>Следующим шагом я попотался сделать так, чтобы код читал директорию и выводил массив файлов. Идея была в том, чтобы избавиться от массива ['en', 'ru'], который должен был создаваться автоматически.</p>
11 <p>Следующим шагом я попотался сделать так, чтобы код читал директорию и выводил массив файлов. Идея была в том, чтобы избавиться от массива ['en', 'ru'], который должен был создаваться автоматически.</p>
12 <p>Тогда я не знал, что Node.JS-модули File System не работают в браузере. Тогда я нашёл полифил<a>browserify-fs</a>, но он не помог решить проблему. Получилось так, что внутри localhost я создал директорию, куда сначала записывал файлы, а затем чистал их, что совершенно бессмысленно.</p>
12 <p>Тогда я не знал, что Node.JS-модули File System не работают в браузере. Тогда я нашёл полифил<a>browserify-fs</a>, но он не помог решить проблему. Получилось так, что внутри localhost я создал директорию, куда сначала записывал файлы, а затем чистал их, что совершенно бессмысленно.</p>
13 <h2>Новая идея</h2>
13 <h2>Новая идея</h2>
14 <p>Затем я решил попробовать сделать так, чтобы дополнительный язык мог добавить не программист, имеющий доступ к файлам проекта, а любой пользователь. Для этого я создал форму загрузки файла и переместил textarea в<a>аккордеон</a>, чтобы не перегружать интерфейс.</p>
14 <p>Затем я решил попробовать сделать так, чтобы дополнительный язык мог добавить не программист, имеющий доступ к файлам проекта, а любой пользователь. Для этого я создал форму загрузки файла и переместил textarea в<a>аккордеон</a>, чтобы не перегружать интерфейс.</p>
15 <p>Кажется, что осталось только реализовать добавление новых локалей в i18next, но это не так. Я знаю, как должен выглядеть файл с текстами, знаю его структуру, а что делать пользователю?</p>
15 <p>Кажется, что осталось только реализовать добавление новых локалей в i18next, но это не так. Я знаю, как должен выглядеть файл с текстами, знаю его структуру, а что делать пользователю?</p>
16 <h2>Добавление примера</h2>
16 <h2>Добавление примера</h2>
17 <p>На экран нужно выводить пример JSON-файла, но как реализовать вывод?</p>
17 <p>На экран нужно выводить пример JSON-файла, но как реализовать вывод?</p>
18 <p><a>Модальное окно</a>добавить просто: оставалось понять, как размещать текст внутри него. У меня был готовый файл<a>example.json</a>с инструкцией на немецком языке. Можно было просто скопировать текст из него в модальное окно, но это неудобно - при изменении текста содержимое модального окна придется менять вручную. Поэтому выброл другой способ:</p>
18 <p><a>Модальное окно</a>добавить просто: оставалось понять, как размещать текст внутри него. У меня был готовый файл<a>example.json</a>с инструкцией на немецком языке. Можно было просто скопировать текст из него в модальное окно, но это неудобно - при изменении текста содержимое модального окна придется менять вручную. Поэтому выброл другой способ:</p>
19 <ul><li>Импортирую JSON-файл, который Webpack конвертирует в обычный JS-объект</li>
19 <ul><li>Импортирую JSON-файл, который Webpack конвертирует в обычный JS-объект</li>
20 <li>Конвертирую объект обратно в JSON</li>
20 <li>Конвертирую объект обратно в JSON</li>
21 <li>Добавляю текст в тег pre для сохранения форматирования.</li>
21 <li>Добавляю текст в тег pre для сохранения форматирования.</li>
22 </ul><p>P.S. Если хотите сохранить отступы, то конвертировать нужно так:</p>
22 </ul><p>P.S. Если хотите сохранить отступы, то конвертировать нужно так:</p>
23 <h2>Валидация</h2>
23 <h2>Валидация</h2>
24 <p>Самая важная и самая сложная часть проекта. Валидацию решил делать асинхронной. Что требовалось проверять?</p>
24 <p>Самая важная и самая сложная часть проекта. Валидацию решил делать асинхронной. Что требовалось проверять?</p>
25 <ul><li>Поле не должно быть пустым</li>
25 <ul><li>Поле не должно быть пустым</li>
26 <li>Только латинские буквы в дополнительных полях ввода</li>
26 <li>Только латинские буквы в дополнительных полях ввода</li>
27 <li>Файл формата JSON</li>
27 <li>Файл формата JSON</li>
28 <li>Размер файла до 2000 Б</li>
28 <li>Размер файла до 2000 Б</li>
29 <li>Правильность JSON-данных.</li>
29 <li>Правильность JSON-данных.</li>
30 </ul><p>Первые пункты довольно просты, а последнему требуется уделить отдельное внимание. Отсановимся на нем подробнее.</p>
30 </ul><p>Первые пункты довольно просты, а последнему требуется уделить отдельное внимание. Отсановимся на нем подробнее.</p>
31 <h3>Валидация JSON</h3>
31 <h3>Валидация JSON</h3>
32 <p>Первым делом нужно быть проверить, что JSON - это действительно JSON. Выбрал проверку парсингом данных: если тест проходит, значит, все в порядке. Еще один тест проверяет наличие необходимых для i18next ключей. В случае ошибки в логе выводится список недостающих ключей.</p>
32 <p>Первым делом нужно быть проверить, что JSON - это действительно JSON. Выбрал проверку парсингом данных: если тест проходит, значит, все в порядке. Еще один тест проверяет наличие необходимых для i18next ключей. В случае ошибки в логе выводится список недостающих ключей.</p>
33 <h3>Локализация ошибок</h3>
33 <h3>Локализация ошибок</h3>
34 <p>Для локалицзации yup через i18next я использовал setLocale(). Но это позволяет получить переводы только для стандартных случаев, но не для тестов получилось добавить переводы только для каких-то стандартных случаев, но не для тестов.</p>
34 <p>Для локалицзации yup через i18next я использовал setLocale(). Но это позволяет получить переводы только для стандартных случаев, но не для тестов получилось добавить переводы только для каких-то стандартных случаев, но не для тестов.</p>
35 <p>Итоговую схему валидации можно посмотреть в файле<a>schema.js</a>.</p>
35 <p>Итоговую схему валидации можно посмотреть в файле<a>schema.js</a>.</p>
36 <h2>Загрузка новых локалей</h2>
36 <h2>Загрузка новых локалей</h2>
37 <p>После завершения подготовительных работ можно приступить к основной функции проекта - добавлению языков.</p>
37 <p>После завершения подготовительных работ можно приступить к основной функции проекта - добавлению языков.</p>
38 <p>Для загрузки используется метод addResourceBundle() библиотеки i18next. После загрузки я обновляю ресурсы с помощью метода reloadResources().</p>
38 <p>Для загрузки используется метод addResourceBundle() библиотеки i18next. После загрузки я обновляю ресурсы с помощью метода reloadResources().</p>
39 <p>Код этой функции представлен в файле<a>handleAddLanguage.js</a>.</p>
39 <p>Код этой функции представлен в файле<a>handleAddLanguage.js</a>.</p>
40 <h3>Toast</h3>
40 <h3>Toast</h3>
41 <p><a>Toast</a>отвечает за всплывающую ошибку в случае, если не удалось загрузить ту или иную локаль С помощью Bootstrap JavaScript реализовать эту функцию было достаточно просто - тем более, что модельное окно управлялось с помощью Bootstrap.</p>
41 <p><a>Toast</a>отвечает за всплывающую ошибку в случае, если не удалось загрузить ту или иную локаль С помощью Bootstrap JavaScript реализовать эту функцию было достаточно просто - тем более, что модельное окно управлялось с помощью Bootstrap.</p>
42 <h3>Дополнения</h3>
42 <h3>Дополнения</h3>
43 <ul><li><strong>Кнопка "Копировать"</strong>. Поскольку копировать текст из модального окна не очень удобно (особенно на телефоне), добавил кнопку копирования примера в буфер обмена.</li>
43 <ul><li><strong>Кнопка "Копировать"</strong>. Поскольку копировать текст из модального окна не очень удобно (особенно на телефоне), добавил кнопку копирования примера в буфер обмена.</li>
44 <li><strong>Блокировка полей</strong>. После успешной загрузки файла кнопка блокируется на пять секунд чтобы нельзя было загрузить что-то еще. Кнопка "копировать в буфер обмена" блокируется на 5 секунд, чтобы пользователь не могу загрузить что-то еще. По той же схеме кнопка блокируется в случае ошибке валидации и отправки данных.</li>
44 <li><strong>Блокировка полей</strong>. После успешной загрузки файла кнопка блокируется на пять секунд чтобы нельзя было загрузить что-то еще. Кнопка "копировать в буфер обмена" блокируется на 5 секунд, чтобы пользователь не могу загрузить что-то еще. По той же схеме кнопка блокируется в случае ошибке валидации и отправки данных.</li>
45 </ul><h2>Итог</h2>
45 </ul><h2>Итог</h2>
46 <p>Работа над проектом заняла у меня гораздо больше времени, чем я рассчитывал. Конечно, на это сильно повлияло то, что я каждый раз добавлял что-то ещё. Зато я узнал много нового: например, как читать файлы или работать с буфером обмена, а также библиотеками yup и i18next, которые пригодятся в работе над<a>RSS агрегатором</a>.</p>
46 <p>Работа над проектом заняла у меня гораздо больше времени, чем я рассчитывал. Конечно, на это сильно повлияло то, что я каждый раз добавлял что-то ещё. Зато я узнал много нового: например, как читать файлы или работать с буфером обмена, а также библиотеками yup и i18next, которые пригодятся в работе над<a>RSS агрегатором</a>.</p>
47 <p>Проект я обязательно добавлю в резюме, а вы можете его посмотреть, перейдя по<a>ссылке</a>. А веб версию<a>здесь</a>.</p>
47 <p>Проект я обязательно добавлю в резюме, а вы можете его посмотреть, перейдя по<a>ссылке</a>. А веб версию<a>здесь</a>.</p>