diff --git a/5-network/09-resume-upload/article.md b/5-network/09-resume-upload/article.md
index 7eedc3fbd..354976bd5 100644
--- a/5-network/09-resume-upload/article.md
+++ b/5-network/09-resume-upload/article.md
@@ -1,36 +1,36 @@
-# Resumable file upload
+# Відновлюване завантаження файлу
 
-With `fetch` method it's fairly easy to upload a file.
+За допомогою методу `fetch` досить легко завантажити файл.
 
-How to resume the upload after lost connection? There's no built-in option for that, but we have the pieces to implement it.
+Але як відновити завантаження після втрати з’єднання? Для цього немає вбудованого функціонала, але у нас є все необхідне для його реалізації.
 
-Resumable uploads should come with upload progress indication, as we expect big files (if we may need to resume). So, as `fetch` doesn't allow to track upload progress, we'll use [XMLHttpRequest](info:xmlhttprequest).
+Відновлювані завантаження файлів повинні мати індикацію прогресу, оскільки ми очікуємо завантаження великих файлів. Отже, оскільки `fetch` не дозволяє відстежувати хід завантаження на сервер, ми будемо використовувати [XMLHttpRequest](info:xmlhttprequest).
 
-## Not-so-useful progress event
+## Не дуже корисна подія progress
 
-To resume upload, we need to know how much was uploaded till the connection was lost.
+Щоб відновити завантаження, нам потрібно знати, скільки даних було завантажено до втрати з’єднання.
 
-There's `xhr.upload.onprogress` to track upload progress.
+Існує подія `xhr.upload.onprogress`, яка використовується для відстежування ходу завантаження на сервер.
 
-Unfortunately, it won't help us to resume the upload here, as it triggers when the data is *sent*, but was it received by the server? The browser doesn't know.
+Але, на жаль, вона нам не допоможе відновити завантаження, оскільки ця подія спрацьовує в момент, коли дані *відсилаються*, але чи отримав їх сервер? Браузер цього не знає.
 
-Maybe it was buffered by a local network proxy, or maybe the remote server process just died and couldn't process them, or it was just lost in the middle and didn't reach the receiver.
+Можливо, дані були буферизовані проксі-сервером локальної мережі, або, можливо, процес сервера просто завершився і не зміг їх обробити, або дані просто загубилися в процесі передачі і не досягли одержувача.
 
-That's why this event is only useful to show a nice progress bar.
+Тому ця подія корисна лише для того, щоб показати гарний індикатор прогресу.
 
-To resume upload, we need to know *exactly* the number of bytes received by the server. And only the server can tell that, so we'll make an additional request.
+Для відновлення завантаження, нам потрібно *точно* знати кількість байтів, отриманих сервером. І тільки сервер має цю інформацію, тому ми зробимо додатковий запит.
 
-## Algorithm
+## Алгоритм
 
-1. First, create a file id, to uniquely identify the file we're going to upload:
+1. Спочатку створюємо ідентифікатор файлу, щоб однозначно ідентифікувати файл, який ми збираємося завантажити на сервер:
     ```js
     let fileId = file.name + '-' + file.size + '-' + file.lastModified;
     ```
-    That's needed for resume upload, to tell the server what we're resuming.
+    Це потрібно, щоб повідомити серверу, для якого саме файлу ми відновлюємо завантаження.
 
-    If the name or the size or the last modification date changes, then there'll be another `fileId`.
+    Якщо змінюється назва, розмір або дата останньої модифікації файлу, `fileId` буде відрізнятися.
 
-2. Send a request to the server, asking how many bytes it already has, like this:
+2. Надсилаємо запит серверу, щоб дізнатися, скільки байтів вже завантажено, наприклад:
     ```js
     let response = await fetch('status', {
       headers: {
@@ -38,45 +38,45 @@ To resume upload, we need to know *exactly* the number of bytes received by the
       }
     });
 
-    // The server has that many bytes
+    // сервер отримав стільки байтів
     let startByte = +await response.text();
     ```
 
-    This assumes that the server tracks file uploads by `X-File-Id` header. Should be implemented at server-side.
+    Передбачається, що сервер відстежує завантаження файлів за допомогою заголовків `X-File-Id`. Це повинно бути реалізовано на стороні сервера.
 
-    If the file doesn't yet exist at the server, then the server response should be `0`
+    Якщо файл ще не існує на сервері, тоді відповідь сервера має бути `0`
 
-3. Then, we can use `Blob` method `slice` to send the file from `startByte`:
+3. Після цього ми можемо використати метод `slice` об’єкта `Blob`, щоб надіслати файл починаючи з байта вказаного в `startByte`:
     ```js
     xhr.open("POST", "upload", true);
 
-    // File id, so that the server knows which file we upload
+    // Ідентифікатор файлу, щоб сервер знав, який файл ми завантажуємо
     xhr.setRequestHeader('X-File-Id', fileId);
 
-    // The byte we're resuming from, so the server knows we're resuming
+    // Байт, починаючи з якого ми відновлюємо завантаження
     xhr.setRequestHeader('X-Start-Byte', startByte);
 
     xhr.upload.onprogress = (e) => {
-      console.log(`Uploaded ${startByte + e.loaded} of ${startByte + e.total}`);
+      console.log(`Завантажено ${startByte + e.loaded} з ${startByte + e.total}`);
     };
 
-    // file can be from input.files[0] or another source
+    // файл може бути з input.files[0] або з іншого джерела
     xhr.send(file.slice(startByte));
     ```
 
-    Here we send the server both file id as `X-File-Id`, so it knows which file we're uploading, and the starting byte as `X-Start-Byte`, so it knows we're not uploading it initially, but resuming.
+    Ми надсилаємо серверу ідентифікатор файлу у заголовку `X-File-Id`, щоб він знав, який саме файл ми завантажуємо, та початковий байт у заголовку `X-Start-Byte`, щоб повідомити, що ми відновлюємо завантаження, а не завантажуємо його спочатку.
 
-    The server should check its records, and if there was an upload of that file, and the current uploaded size is exactly `X-Start-Byte`, then append the data to it.
+    Сервер повинен перевірити свої записи, і якщо було завантаження цього файлу, а також поточний розмір завантаженого файлу точно дорівнює `X-Start-Byte`, то додати дані до нього.
 
 
-Here's the demo with both client and server code, written on Node.js.
+Ось приклад з кодом клієнта і сервера, написаний на Node.js.
 
-It works only partially on this site, as Node.js is behind another server named Nginx, that buffers uploads, passing them to Node.js when fully complete.
+На цьому сайті він працює лише частково, оскільки Node.js знаходиться за іншим сервером під назвою Nginx, який буферує завантаження і передає їх у Node.js тільки після повного завершення.
 
-But you can download it and run locally for the full demonstration:
+Але ви можете завантажити та запустити його локально для повної демонстрації:
 
 [codetabs src="upload-resume" height=200]
 
-As we can see, modern networking methods are close to file managers in their capabilities -- control over headers, progress indicator, sending file parts, etc.
+Як бачимо, сучасні мережеві методи за своїми можливостями близькі до файлових менеджерів -- контроль над заголовками, індикатор прогресу, надсилання частин файлу тощо.
 
-We can implement resumable upload and much more.
+Ми можемо реалізувати як відновлюване завантаження файлів, так і багато іншого.
diff --git a/5-network/09-resume-upload/upload-resume.view/index.html b/5-network/09-resume-upload/upload-resume.view/index.html
index f1178145e..4eca9eb58 100644
--- a/5-network/09-resume-upload/upload-resume.view/index.html
+++ b/5-network/09-resume-upload/upload-resume.view/index.html
@@ -4,13 +4,13 @@
 
 <form name="upload" method="POST" enctype="multipart/form-data" action="/https/patch-diff.githubusercontent.com/upload">
   <input type="file" name="myfile">
-  <input type="submit" name="submit" value="Upload (Resumes automatically)">
+  <input type="submit" name="submit" value="Завантажити файл (відновлюється автоматично)">
 </form>
 
-<button onclick="uploader.stop()">Stop upload</button>
+<button onclick="uploader.stop()">Зупинити завантаження</button>
 
 
-<div id="log">Progress indication</div>
+<div id="log">Індикація прогресу</div>
 
 <script>
   function log(html) {
@@ -19,7 +19,7 @@
   }
 
   function onProgress(loaded, total) {
-    log("progress " + loaded + ' / ' + total);
+    log("завантажується " + loaded + ' / ' + total);
   }
 
   let uploader;
@@ -36,14 +36,14 @@
       let uploaded = await uploader.upload();
 
       if (uploaded) {
-        log('success');
+        log('успішно');
       } else {
-        log('stopped');
+        log('зупинено');
       }
 
     } catch(err) {
       console.error(err);
-      log('error');
+      log('помилка');
     }
   };
 
diff --git a/5-network/09-resume-upload/upload-resume.view/server.js b/5-network/09-resume-upload/upload-resume.view/server.js
index 83ce59f7a..34e43c05a 100644
--- a/5-network/09-resume-upload/upload-resume.view/server.js
+++ b/5-network/09-resume-upload/upload-resume.view/server.js
@@ -17,14 +17,14 @@ function onUpload(req, res) {
     res.end();
   }
 
-  // we'll files "nowhere"
+  // ми будемо зберігати файли в "нікуди"
   let filePath = '/dev/null';
-  // could use a real path instead, e.g.
+  // замість цього можна використовувати реальний шлях, наприклад
   // let filePath = path.join('/tmp', fileId);
 
   debug("onUpload fileId: ", fileId);
 
-  // initialize a new upload
+  // ініціалізуємо нове завантаження
   if (!uploads[fileId]) uploads[fileId] = {};
   let upload = uploads[fileId];
 
@@ -32,7 +32,7 @@ function onUpload(req, res) {
 
   let fileStream;
 
-  // if startByte is 0 or not set, create a new file, otherwise check the size and append to existing one
+  // якщо startByte не встановлений або дорівнює 0, то створюємо новий файл, в противному випадку перевіряємо розмір і додаємо дані до наявного файлу
   if (!startByte) {
     upload.bytesReceived = 0;
     fileStream = fs.createWriteStream(filePath, {
@@ -40,13 +40,13 @@ function onUpload(req, res) {
     });
     debug("New file created: " + filePath);
   } else {
-    // we can check on-disk file size as well to be sure
+    // ми також можемо перевірити розмір файлу на диску, щоб бути впевненими
     if (upload.bytesReceived != startByte) {
       res.writeHead(400, "Wrong start byte");
       res.end(upload.bytesReceived);
       return;
     }
-    // append to existing file
+    // додати дані до наявного файлу
     fileStream = fs.createWriteStream(filePath, {
       flags: 'a'
     });
@@ -59,26 +59,26 @@ function onUpload(req, res) {
     upload.bytesReceived += data.length;
   });
 
-  // send request body to file
+  // відправляємо тіло запиту у файл
   req.pipe(fileStream);
 
-  // when the request is finished, and all its data is written
+  // коли запит буде завершено, і всі його дані будуть записані
   fileStream.on('close', function() {
     if (upload.bytesReceived == req.headers['x-file-size']) {
       debug("Upload finished");
       delete uploads[fileId];
 
-      // can do something else with the uploaded file here
+      // тут можна зробити ще щось інше із завантаженим файлом
 
       res.end("Success " + upload.bytesReceived);
     } else {
-      // connection lost, we leave the unfinished file around
+      // з’єднання втрачено, ми зберігаємо незавершений файл
       debug("File unfinished, stopped at " + upload.bytesReceived);
       res.end();
     }
   });
 
-  // in case of I/O error - finish the request
+  // у разі помилки введення/виводу - завершити запит
   fileStream.on('error', function(err) {
     debug("fileStream error");
     res.writeHead(500, "File error");
diff --git a/5-network/09-resume-upload/upload-resume.view/uploader.js b/5-network/09-resume-upload/upload-resume.view/uploader.js
index 10002039c..71e9dd3e2 100644
--- a/5-network/09-resume-upload/upload-resume.view/uploader.js
+++ b/5-network/09-resume-upload/upload-resume.view/uploader.js
@@ -4,8 +4,8 @@ class Uploader {
     this.file = file;
     this.onProgress = onProgress;
 
-    // create fileId that uniquely identifies the file
-    // we could also add user session identifier (if had one), to make it even more unique
+    // створюємо fileId, який однозначно ідентифікує файл
+    // ми також могли б додати ідентифікатор сесії користувача (якщо він є), щоб зробити його ще більш унікальним
     this.fileId = file.name + '-' + file.size + '-' + file.lastModified;
   }
 
@@ -31,9 +31,9 @@ class Uploader {
     let xhr = this.xhr = new XMLHttpRequest();
     xhr.open("POST", "upload", true);
 
-    // send file id, so that the server knows which file to resume
+    // надсилаємо ідентифікатор файлу, щоб сервер знав, завантаження якого файлу ми відновлюємо
     xhr.setRequestHeader('X-File-Id', this.fileId);
-    // send the byte we're resuming from, so the server knows we're resuming
+    // надсилаємо байт, з якого ми відновлюємо завантаження
     xhr.setRequestHeader('X-Start-Byte', this.startByte);
 
     xhr.upload.onprogress = (e) => {
@@ -43,10 +43,10 @@ class Uploader {
     console.log("send the file, starting from", this.startByte);
     xhr.send(this.file.slice(this.startByte));
 
-    // return
-    //   true if upload was successful,
-    //   false if aborted
-    // throw in case of an error
+    // повертає
+    //   true якщо завантаження було успішним,
+    //   false якщо перервано
+    // throw в разі помилки
     return await new Promise((resolve, reject) => {
 
       xhr.onload = xhr.onerror = () => {
@@ -59,7 +59,7 @@ class Uploader {
         }
       };
 
-      // onabort triggers only when xhr.abort() is called
+      // onabort запускається лише тоді, коли викликається xhr.abort()
       xhr.onabort = () => resolve(false);
 
     });