Google 幻灯片编辑器插件快速入门

本快速入门将创建一个 Google 幻灯片编辑器插件,用于翻译演示文稿中所选文字。

目标

  • 设置脚本。
  • 运行脚本。

前提条件

如需使用此示例,您需要满足以下前提条件:

  • Google 账号(Google Workspace 账号可能需要管理员批准)。
  • 一个能够访问互联网的网络浏览器。

设置脚本

  1. 前往 slides.new 创建幻灯片演示文稿。
  2. 依次点击扩展程序 > Google Apps 脚本
  3. 点击无标题项目
  4. 将 Apps 脚本项目重命名为翻译幻灯片,然后点击重命名
  5. Code.gs 文件旁边,依次点击“更多”图标 > 重命名。将文件命名为 translate
  6. 依次点击“添加文件”图标 > HTML。将文件命名为 sidebar
  7. 将每个文件的内容替换为以下相应代码,然后点击“保存”图标 “保存”图标

    translate.gs

    slides/translate/translate.gs
    /**
     * @OnlyCurrentDoc Limits the script to only accessing the current presentation.
     */
    
    /**
     * Create a open translate menu item.
     * @param {Event} event The open event.
     */
    function onOpen(event) {
      SlidesApp.getUi().createAddonMenu()
          .addItem('Open Translate', 'showSidebar')
          .addToUi();
    }
    
    /**
     * Open the Add-on upon install.
     * @param {Event} event The install event.
     */
    function onInstall(event) {
      onOpen(event);
    }
    
    /**
     * Opens a sidebar in the document containing the add-on's user interface.
     */
    function showSidebar() {
      const ui = HtmlService
          .createHtmlOutputFromFile('sidebar')
          .setTitle('Translate');
      SlidesApp.getUi().showSidebar(ui);
    }
    
    /**
     * Recursively gets child text elements a list of elements.
     * @param {PageElement[]} elements The elements to get text from.
     * @return {Text[]} An array of text elements.
     */
    function getElementTexts(elements) {
      let texts = [];
      elements.forEach((element)=> {
        switch (element.getPageElementType()) {
          case SlidesApp.PageElementType.GROUP:
            element.asGroup().getChildren().forEach((child)=> {
              texts = texts.concat(getElementTexts(child));
            });
            break;
          case SlidesApp.PageElementType.TABLE:
            const table = element.asTable();
            for (let y = 0; y < table.getNumColumns(); ++y) {
              for (let x = 0; x < table.getNumRows(); ++x) {
                texts.push(table.getCell(x, y).getText());
              }
            }
            break;
          case SlidesApp.PageElementType.SHAPE:
            texts.push(element.asShape().getText());
            break;
        }
      });
      return texts;
    }
    
    /**
     * Translates selected slide elements to the target language using Apps Script's Language service.
     *
     * @param {string} targetLanguage The two-letter short form for the target language. (ISO 639-1)
     * @return {number} The number of elements translated.
     */
    function translateSelectedElements(targetLanguage) {
      // Get selected elements.
      const selection = SlidesApp.getActivePresentation().getSelection();
      const selectionType = selection.getSelectionType();
      let texts = [];
      switch (selectionType) {
        case SlidesApp.SelectionType.PAGE:
          selection.getPageRange().getPages().forEach((page)=> {
            texts = texts.concat(getElementTexts(page.getPageElements()));
          });
          break;
        case SlidesApp.SelectionType.PAGE_ELEMENT:
          const pageElements = selection.getPageElementRange().getPageElements();
          texts = texts.concat(getElementTexts(pageElements));
          break;
        case SlidesApp.SelectionType.TABLE_CELL:
          selection.getTableCellRange().getTableCells().forEach((cell)=> {
            texts.push(cell.getText());
          });
          break;
        case SlidesApp.SelectionType.TEXT:
          selection.getPageElementRange().getPageElements().forEach((element) =>{
            texts.push(element.asShape().getText());
          });
          break;
      }
    
      // Translate all elements in-place.
      texts.forEach((text)=> {
        text.setText(LanguageApp.translate(text.asRenderedString(), '', targetLanguage));
      });
    
      return texts.length;
    }

    sidebar.html

    slides/translate/sidebar.html
    <html>
    <head>
      <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
      <style>
        .logo { vertical-align: middle; }
        ul { list-style-type: none; padding: 0; }
        h4 { margin: 0; }
      </style>
    </head>
    <body>
    <form class="sidebar branding-below">
      <h4>Translate selected slides into:</h4>
      <ul id="languages"></ul>
      <div class="block" id="button-bar">
        <button class="blue" id="run-translation">Translate</button>
      </div>
      <h5 class="error" id="error"></h5>
    </form>
    <div class="sidebar bottom">
      <img alt="Add-on logo" class="logo"
           src="https://www.gstatic.com/images/branding/product/1x/translate_48dp.png" width="27" height="27">
      <span class="gray branding-text">Translate sample by Google</span>
    </div>
    
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script>
      $(function() {
        // Add an input radio button for every language.
        const languages = {
          ar: 'Arabic',
          zh: 'Chinese',
          en: 'English',
          fr: 'French',
          de: 'German',
          hi: 'Hindi',
          ja: 'Japanese',
          pt: 'Portuguese',
          es: 'Spanish'
        };
        const languageList = Object.keys(languages).map((id)=> {
          return $('<li>').html([
            $('<input>')
                    .attr('type', 'radio')
                    .attr('name', 'dest')
                    .attr('id', 'radio-dest-' + id)
                    .attr('value', id),
            $('<label>')
                    .attr('for', 'radio-dest-' + id)
                    .html(languages[id])
          ]);
        });
    
        $('#run-translation').click(runTranslation);
        $('#languages').html(languageList);
      });
    
      /**
       * Runs a server-side function to translate the text on all slides.
       */
      function runTranslation() {
        this.disabled = true;
        $('#error').text('');
        google.script.run
                .withSuccessHandler((numTranslatedElements, element) =>{
                  element.disabled = false;
                  if (numTranslatedElements === 0) {
                    $('#error').empty()
                            .append('Did you select elements to translate?')
                            .append('<br/>')
                            .append('Please select slides or individual elements.');
                  }
                  return false;
                })
                .withFailureHandler((msg, element)=> {
                  element.disabled = false;
                  $('#error').text('Something went wrong. Please check the add-on logs.');
                  return false;
                })
                .withUserObject(this)
                .translateSelectedElements($('input[name=dest]:checked').val());
      }
    </script>
    </body>
    </html>

运行脚本

  1. 在幻灯片演示文稿中,重新加载页面。
  2. 依次点击扩展程序 > 翻译幻灯片 > 开始。插件菜单项可能需要几秒钟才能显示。
  3. 出现提示时,为该插件授权。
  4. 再次依次点击扩展程序 > 翻译幻灯片 > 开始
  5. 在演示文稿中添加文本,然后选择该文本。
  6. 在该插件中,点击翻译以替换所选文本。

后续步骤