Töötamine onEdit päästiku (reaktsioon muudatustele tabelis) ja LanguageApp klassiga (teksti tõlkimine Google Spreadsheetsis)



Mida see kood teeb?

See skript töötab automaatselt, kui kasutaja sisestab andmeid Google Sheetsi lahtrisse.

  • Käivitatakse onEdit(e) funktsioon, kui kasutaja muudab lahtrit
  • Kontrollitakse, millisel lehel muudatus toimus:
    • Kui lehe nimi ei ole "Перевод текста" (Tõlketekst), siis skript peatub
  • Kontrollitakse, kas muudatus toimus esimeses veerus:
    • Kui muudatus ei ole esimeses veerus, siis skript peatub
  • Tõlgib venekeelse teksti inglise keelde:
    • Loeb venekeelse teksti esimesest veerust
    • Kasutab Google’i keele API-t (LanguageApp.translate()), et tõlkida vene keelest inglise keelde
  • Salvestab tõlgitud teksti teise veergu (samas reas)

Tulemus

Kohandatud koodi muutmine

  • Lisatud uued muutujad translatedText2, translatedText3 ja translatedText4, et salvestada erinevatesse keeltesse tõlgitud tekst

  • Ingliskeelne tõlge salvestatakse 2. veergu
  • Prantsusekeelne tõlge salvestatakse 3. veergu
  • Jaapanikeelne tõlge salvestatakse 4. veergu
  • Lätikeelne tõlge salvestatakse 5. veergu

Tulemus

Originaal kood

// Функция onEdit является триггером, который срабатывает при завершении ввода данных в ячейку Таблицы пользователем
// https://developers.google.com/apps-script/guides/triggers/#onedite
function onEdit(e) {
  Logger.log(e);

  // Получаем диапазон ячеек, в которых произошли изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/range
  var range = e.range;

  // Лист, на котором производились изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/sheet
  var sheet = range.getSheet();

  // Проверяем, нужный ли это нам лист
  Logger.log(sheet.getName());
  if (sheet.getName() != 'Перевод текста') {
    return false;
  }

  // Переводить необходимо текст, введённый только в первую колонку.
  // Проверяем стартовую позицию диапазона
  Logger.log(range.getColumn());
  if  (range.getColumn() != 1) {
    return false;
  }

  for (var i = 1; i <= range.getNumRows(); i++) {
    var cell = range.getCell(
      i, // номер строки
      1 // номер колонки
    );

    // Получаем текст на русском
    var russianText = cell.getValue();

    // Переводим текст на английский
    // https://developers.google.com/apps-script/reference/language/language-app
    var translatedText = LanguageApp.translate(
      russianText, // текст
      'ru', // с какого языка переводим
      'en' // на какой язык переводим
    );

    // Вставляем переведённый текст во вторую колонку
    sheet.getRange(
      cell.getRowIndex(), // номер строки
      2 // номер столбца
    ).setValue(translatedText);
  }

}

Uus kood muudatusega

// Функция onEdit является триггером, который срабатывает при завершении ввода данных в ячейку Таблицы пользователем
// https://developers.google.com/apps-script/guides/triggers/#onedite
function onEdit(e) {
  Logger.log(e);

  // Получаем диапазон ячеек, в которых произошли изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/range
  var range = e.range;

  // Лист, на котором производились изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/sheet
  var sheet = range.getSheet();

  // Проверяем, нужный ли это нам лист
  Logger.log(sheet.getName());
  if (sheet.getName() != 'Перевод текста') {
    return false;
  }

  // Переводить необходимо текст, введённый только в первую колонку.
  // Проверяем стартовую позицию диапазона
  Logger.log(range.getColumn());
  if  (range.getColumn() != 1) {
    return false;
  }

  for (var i = 1; i <= range.getNumRows(); i++) {
    var cell = range.getCell(
      i, // номер строки
      1 // номер колонки
    );

    // Получаем текст на русском
    var russianText = cell.getValue();

    // Переводим текст на английский
    // https://developers.google.com/apps-script/reference/language/language-app
    // https://cloud.google.com/translate/docs/languages
    let translatedText = LanguageApp.translate(
      russianText, // текст
      'ru', // с какого языка переводим
      'en' // на какой язык переводим
    );
    let translatedText2 = LanguageApp.translate(
      russianText, // текст
      'ru', // с какого языка переводим
      'fr' // на какой язык переводим
    );
    let translatedText3 = LanguageApp.translate(
      russianText, // текст
      'ru', // с какого языка переводим
      'ja' // на какой язык переводим
    );
    let translatedText4 = LanguageApp.translate(
      russianText, // текст
      'ru', // с какого языка переводим
      'lv' // на какой язык переводим
    );

    // Вставляем переведённый текст во вторую колонку
    sheet.getRange(
      cell.getRowIndex(), // номер строки
      2 // номер столбца
    ).setValue(translatedText);

    // Вставляем переведённый текст в третью колонку
    sheet.getRange(
      cell.getRowIndex(), // номер строки
      3 // номер столбца
    ).setValue(translatedText2);

    // Вставляем переведённый текст в четвертую колонку
    sheet.getRange(
      cell.getRowIndex(), // номер строки
      4 // номер столбца
    ).setValue(translatedText3);

    // Вставляем переведённый текст в четвертую колонку
    sheet.getRange(
      cell.getRowIndex(), // номер строки
      5 // номер столбца
    ).setValue(translatedText4);
  }
}

Тöö HTML-teenusega (modaali ja külgriba kuvamine Google Spreadsheetis)

  • Loob HTML-koodi külgriba (sidebar) jaoks:
    • Lisab Bootstrapi ja jQuery
    • Loob HTML-vormi järgmiste väljadega:
      • Nimi (name)
      • Tekstiväli (abrakadabra)
      • Reanumber (strNum)
  • Lisab kaks nuppu:
    • “Salvesta andmed tabelisse” – saadab andmed Google Sheetsi
    • “Sulge külgriba” – sulgeb külgriba
  • Lisab JavaScripti koodi sündmuste töötlemiseks:
    • Vormis sisestatud andmed saadetakse funktsioonile writeStrInTable(), mis salvestab need tabelisse
    • Kui vajutada nuppu “Sulge külgriba”, siis paneel suletakse
  • Avab külgriba Google Sheetsi aknas
  • Võtab vormist saadud andmed (nimi, tekst, reanumber)
  • Leiab aktiivse töölehe Google Sheetsis
  • Salvestab andmed õigesse ritta:
    • Nimi → veerg A.
    • Tekst → veerg B.
  • Tagastab eduteate (“Kõik õnnestus!”)

Tulemus

Google Apps Script

Kohandatud koodi muutmine

  • Lisatud küsimus: “Вам нравится данная форма?”
  • Kasutaja saab valida “Да” või “Нет”, kasutades raadionuppe (<input type="radio">)

  • JavaScriptis lisatud raadionuppude väärtuse (jahEi) saatmine funktsioonile writeStrInTable(
  • Kasutatakse jQuery-d $('input[name=jahEi]:checked').val(), et leida valitud vastus

  • Funktsioon writeStrInTable(e) võtab vastu uue muutuja radioNupp, mis sisaldab kasutaja valikut (“Да” või “Нет”)
  • See väärtus lisatakse uude veergu C (sheet.getRange("C" + strNum).setValue(radioNupp))

Tulemus

Google Apps Script

Originaal kood

// Открытие сайдбара
function showSidebar() {
 
    // Подключаем Bootstrap
    var sidebarHTML = '&lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">';
    // Подключаем jQuery
    sidebarHTML += '&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">&lt;/script>';
 
    // Создаём форму
    sidebarHTML += '&lt;form style="padding: 20px;text-align:center;">
        &lt;div class="form-group">
            &lt;label for="name">Имя&lt;/label>
            &lt;input type="text" class="form-control" id="name" name="name" value="">
        &lt;/div>
        &lt;div class="form-group">
            &lt;label for="abrakadabra">Какая-то абракадабра&lt;/label>
            &lt;textarea class="form-control" id="abrakadabra" name="abrakadabra" rows="3">&lt;/textarea> 
        &lt;/div>
        &lt;div class="form-group">
            &lt;label for="strNum">Номер строки, в которую необходимо внести данные&lt;/label>
            &lt;input type="text" class="form-control" id="strNum" name="strNum" value="">
        &lt;/div>
        &lt;button type="submit" class="btn btn-primary">Записать данные в таблицу&lt;/button>
        &lt;br>&lt;br>&lt;br>
        &lt;button type="button" id="sidebarClose" class="btn btn-danger">Закрыть сайдбар&lt;/button>
    &lt;/form>';
 
    // Добавляем скрипты
    // При сабмите формы вызываем функцию writeStrInTable() и передаём ей введённые данные
    // https://developers.google.com/apps-script/guides/html/reference/run
    // При клике на кнопку 'Закрыть сайдбар' закрываем его
    // https://developers.google.com/apps-script/guides/html/reference/host#close()
    sidebarHTML += "&lt;script>
     $(document).on('submit', 'form', function () { 
        google.script.run 
     .withSuccessHandler(function (resultMsg) { 
                  alert(resultMsg);
         })
     .writeStrInTable(
                { name: $('#name').val(), abrakadabra: $('#abrakadabra').val(), strNum: $('#strNum').val() }
     );
        return false;
     });

     $('#sidebarClose').on('click', function() {
        google.script.host.close();
     });
     &lt;/script>";
 
 
    var htmlOutput = HtmlService
        .createHtmlOutput(sidebarHTML)
        .setTitle('My add-on');
 
// https://developers.google.com/apps-script/reference/base/ui#showsidebaruserinterface
    SpreadsheetApp.getUi().showSidebar(htmlOutput);
 
}
 
function writeStrInTable(e) {
    var name = e.name;
    var abrakadabra = e.abrakadabra;
    var strNum = parseInt(e.strNum);
 
    // Получаем объект с активной (открытой в данный момент) таблицей
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = ss.getActiveSheet();
 
    // Записываем полученные данные в таблицу
    sheet.getRange("A" + strNum).setValue(name);
    sheet.getRange("B" + strNum).setValue(abrakadabra);
 
    return "Всё прошло успешно!";
}

Uus kood muudatusega

// Открытие сайдбара
function showSidebar() {

    // Подключаем Bootstrap
    var sidebarHTML = '&lt;link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">';
    // Подключаем jQuery
    sidebarHTML += '&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">&lt;/script>';

    // Создаём форму
    sidebarHTML += '&lt;form style="padding: 20px;text-align:center;">
        &lt;div class="form-group">
            &lt;label for="name">Имя&lt;/label>
            &lt;input type="text" class="form-control" id="name" name="name" value="">
        &lt;/div>
        &lt;div class="form-group">
            &lt;label for="abrakadabra">Какая-то абракадабра&lt;/label>
            &lt;textarea class="form-control" id="abrakadabra" name="abrakadabra" rows="3">&lt;/textarea> 
        &lt;/div>
        &lt;div class="form-group">
            &lt;label for="strNum">Номер строки, в которую необходимо внести данные&lt;/label>
            &lt;input type="text" class="form-control" id="strNum" name="strNum" value="">
        &lt;/div>
        &lt;div class="form-group">
            &lt;label>Вам нравится данная форма?&lt;/label>&lt;br>
            &lt;input type="radio" id="yes" name="jahEi" value="да">
            &lt;label for="yes">Да&lt;/label>&lt;br>
            &lt;input type="radio" id="no" name="jahEi" value="нет">
            &lt;label for="no">Нет&lt;/label>&lt;br>
        &lt;/div>
        &lt;button type="submit" class="btn btn-primary">Записать данные в таблицу&lt;/button>
        &lt;br>&lt;br>&lt;br>
        &lt;button type="button" id="sidebarClose" class="btn btn-danger">Закрыть сайдбар&lt;/button>
    &lt;/form>';

    // Добавляем скрипты
    sidebarHTML += "&lt;script>
     $(document).on('submit', 'form', function () { 
        google.script.run 
     .withSuccessHandler(function (resultMsg) { 
                  alert(resultMsg);
         })
     .writeStrInTable(
                { name: $('#name').val(), abrakadabra: $('#abrakadabra').val(), strNum: $('#strNum').val(), jahEi: $('input[name=jahEi]:checked').val() }
     );
        return false;
     });

     $('#sidebarClose').on('click', function() {
        google.script.host.close();
     });
     &lt;/script>";

    var htmlOutput = HtmlService
        .createHtmlOutput(sidebarHTML)
        .setTitle('My add-on');

    SpreadsheetApp.getUi().showSidebar(htmlOutput);
}

function writeStrInTable(e) {
    var name = e.name;
    var abrakadabra = e.abrakadabra;
    var strNum = parseInt(e.strNum);
    var radioNupp = e.jahEi;

    // Получаем объект с активной (открытой в данный момент) таблицей
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var sheet = ss.getActiveSheet();

    // Записываем полученные данные в таблицу
    sheet.getRange("A" + strNum).setValue(name);
    sheet.getRange("B" + strNum).setValue(abrakadabra);
    sheet.getRange("C" + strNum).setValue(radioNupp);

    return "Всё прошло успешно!";
}

Veebisaitide pealkirjade parsimine

Mida see kood teeb?

  • Leiab lehe nimega "list"
  • Võtab esimese veeru URL-id (veebilehtede aadressid)
  • Võtab ühe lingi ja saadab sellele päringu
  • Kui sait ei avane, kirjutab tabelisse vea
  • Kui sait avaneb, kontrollib lehe kodeeringut

Google Apps Script konspekt
  • Kui pealkiri leitakse, kirjutab selle teise veergu
  • Kui pealkirja ei leita, kirjutab tabelisse vea


Tulemus

Google Apps Script konspekt

Kohandatud koodi muutmine

  • Lisatud kood, mis otsib lehelt footer osa, kasutades regulaaravaldist (/<footer[^>]*>([\s\S]*?)<\/footer>/i)
  • Kui footer leiti, eemaldatakse kõik HTML sildid ja saadakse puhas tekst, mis siis salvestatakse Google Sheetsi. ( footer.replace(/<[^>]*>/g, '').trim(); )
  • Täiendavalt on lisatud kood, mis asendab kõik &copy; HTML entiteedid sümboliga ©: ( footerText.replace(/&copy;/g, '©'); )

  • Kui lehelt leiti footer, siis selle tekst lisatakse uude veergu 3 (koodis sheet.getRange(i + 1, 3).setValue(footerText))

  • Funktsioon insertError on muudetud, et ta saaks lisada veateate mitte ainult veergu 2, vaid ka veergu 3
    • Parameeter numColumn on lisatud, et määrata veerg, kuhu veateade kirjutatakse

  • Kui title või footer ei leita, siis kirjutatakse veateade vastavatesse veergudesse (veerg 2 ja veerg 3)

Tulemus

Originaal kood

function parser() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('list');
  var values = sheet.getDataRange().getValues();

  var insertError = function(msg, numRow) {
    sheet.getRange(numRow, 2).setValue('ОШИБКА! ' + msg).setBackground('red');
  }

  var rowNumStart = 1; // Номер строки, с которой необходимо начать парсинг

  for (var i = rowNumStart; i < values.length; i++) {

    var url = values[i][0];

    try {

      var response = UrlFetchApp.fetch(url, {
      'muteHttpExceptions': true,
      'validateHttpsCertificates': false,
      'followRedirects': true,
    }); // Загружаем страницу по указанному url

    } catch(e) {
      insertError(e, i+1);
      continue;
    }


    // https://developers.google.com/apps-script/reference/url-fetch/http-response
    var responseCode = response.getResponseCode(); // Код ответа сервера

    if (responseCode === 200) {

      try {
        var headers = response.getHeaders();
        var charset = headers['Content-Type'].match(/charset=(.*)$/)[1].replace(/[";]+/gi, ''); // Кодировка страницы
      } catch (e) {
        var contentForCharset = response.getContentText();
        var charsetMatch = contentForCharset.match(/charset=(.*?)"/);
        var charset = (charsetMatch !== null) ? charsetMatch[1] : "UTF-8";
      }

      var content = response.getContentText(charset); // Получаем html код страницы

      // Получаем название поста
      var titleMatch = content.match(/<title[^>]*>\s*([\s\S]*?)\s*</);

if (titleMatch !== null) {
var title = titleMatch[1];

// Вставляем название в таблицу
sheet.getRange(i+1,2).setValue(title);

} else {
insertError('Не удалось распарсить title.', i+1);
}

} else {
insertError('Код ответа сервера != 200.', i+1);
}

}

}

Uus kood muudatusega

function parser() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('list');
  var values = sheet.getDataRange().getValues();

  var insertError = function(msg, numRow, numColumn) {
    sheet.getRange(numRow, numColumn).setValue('ОШИБКА! ' + msg).setBackground('red');
  }

  var rowNumStart = 1; // Номер строки, с которой необходимо начать парсинг

  for (var i = rowNumStart; i < values.length; i++) {

    var url = values[i][0];

    try {

      var response = UrlFetchApp.fetch(url, {
      'muteHttpExceptions': true,
      'validateHttpsCertificates': false,
      'followRedirects': true,
    }); // Загружаем страницу по указанному url

    } catch(e) {
      insertError(e, i+1, 2);
      continue;
    }


    // https://developers.google.com/apps-script/reference/url-fetch/http-response
    var responseCode = response.getResponseCode(); // Код ответа сервера

    if (responseCode === 200) {

      try {
        var headers = response.getHeaders();
        var charset = headers['Content-Type'].match(/charset=(.*)$/)[1].replace(/[";]+/gi, ''); // Кодировка страницы
      } catch (e) {
        var contentForCharset = response.getContentText();
        var charsetMatch = contentForCharset.match(/charset=(.*?)"/);
        var charset = (charsetMatch !== null) ? charsetMatch[1] : "UTF-8";
      }

      var content = response.getContentText(charset); // Получаем html код страницы

       // Получаем название поста
      var titleMatch = content.match(/<title[^>]*>\s*([\s\S]*?)\s*</);
      var footerMatch = content.match(/<footer[^>]*>([\s\S]*?)<\/footer>/i);

if (titleMatch !== null) {
  var title = titleMatch[1];
  
  // Вставляем название
  sheet.getRange(i + 1, 2).setValue(title);

} else {
  insertError('Не удалось распарсить title', i + 1, 2);
}

if (footerMatch !== null) {
  var footer = footerMatch[1];

  // Убираем все HTML теги из текста футера
  // Источник https://www.w3schools.com/jsref/jsref_trim_string.asp
  var footerText = footer.replace(/<[^>]*>/g, '').trim();
  footerText = footerText.replace(/&copy;/g, '©');

  sheet.getRange(i + 1, 3).setValue(footerText);

} else {
  insertError('Не удалось распарсить footer', i + 1, 3);
}

} else {
insertError('Код ответа сервера != 200', i + 1, 2);
}

}
}