本文へスキップ
ロケット団合同会社
Studioカスタムコード外部ツール

Studio完全解説|スプレッドシートで多言語対応の実装手順

Studioには標準の多言語化機能がありません。スプレッドシート×GAS×ID差し替え方式で、Studioの構造を崩さずに翻訳管理を外部化する実務的な多言語対応の実装手順を解説します。

公開 2026年3月14日更新 2026年3月14日読了目安 約7

Studioで作ったサイトの多言語対応の方法でお悩みを持つユーザーは多いです。海外ユーザーへの発信やインバウンド対応を考えると、サイトの多言語化は必須テーマです。

Studioには標準でサイト全体をワンクリックで多言語化できる機能はありません。そのため多言語サイトを構築しようとすると、次のような課題が発生します。

  • 言語ごとにページを複製する必要がある😵
  • 翻訳修正のたびに複数ページを修正する必要がある🔧
  • 外部サービス(Weglotなど)はコストがかかる💰

サイト規模が大きくなるほど、運用コストは確実に増加します。この記事では、Studioの構造を崩さずに多言語対応を実現する、実務的な方法として「ID差し替え方式」を解説します。

全体構成 🧩

スプレッドシートを使ったStudioサイトの多言語化の全体構成は以下の通りです。

Google Spreadsheet(翻訳マスタ) ↓ Google Apps Script(JSON API) ↓ Studio(ID一致でテキスト差し替え)

この構成の最大の特徴は、翻訳管理をStudioの外に完全に分離できることです✨

それでは、全5ステップに分けて多言語化を実装していきましょう。

STEP1 |翻訳マスタを作成する 📊

手順1|新規に翻訳マスタとなるGoogleスプレッドシートを作成します。

Googleスプレッドシートで空白のスプレッドシートを新規作成
Googleスプレッドシートで空白のスプレッドシートを新規作成

手順2|シート名をi18nに変更します。

シートタブ名をi18nに変更した状態
シートタブ名をi18nに変更した状態

手順3|翻訳マスタを以下のカラム構成で作成します。

keyjaenzh
hero_title理想のサイトをBuild your ideal website打造理想網站
cta_buttonまずは無料相談Free consultation免費諮詢

以下のように、日本語、英語、中国語をそれぞれのkeyに対応するように翻訳マスタを作成します。

key/ja/en/zh列で構成された翻訳マスタの完成イメージ
key/ja/en/zh列で構成された翻訳マスタの完成イメージ
key設計ルール
  • 半角英数字+アンダースコアのみ使用
  • ページ単位で命名すると管理しやすい

例:home_hero_titlenav_homeblog_title

STEP2|GASで翻訳JSON APIを作成する ⚡

手順1|拡張機能「Apps Script」を使って翻訳マスタをJSON配信します。

スプレッドシートの「拡張機能」メニューからApps Scriptを選択
スプレッドシートの「拡張機能」メニューからApps Scriptを選択

手順2|コードの内容を以下のように書き換えます。最初に自動で入っているfunction myFunction() {}などのコードは削除してOKです。コードの中の「スプレッドシートID」に、ご自身のスプレッドシートIDを入力してください。

スプレッドシートURL内の「d/」と「/edit?」の間の文字列がIDです。

https://docs.google.com/spreadsheets/d/スプレッドシートID/edit?pli=1&gid=0#gid=0
function doGet(e) {
  var lang = (e && e.parameter && e.parameter.lang) ? String(e.parameter.lang) : "ja";

  var sheet = SpreadsheetApp
    .openById("スプレッドシートID")
    .getSheetByName("i18n");

  var values = sheet.getDataRange().getValues();
  var headers = values.shift(); // [key, ja, en, zh...]

  var keyIndex = 0;
  var langIndex = headers.indexOf(lang);
  if (langIndex === -1) langIndex = headers.indexOf("ja");

  var dict = {};
  for (var i = 0; i < values.length; i++) {
    var row = values[i];
    var k = row[keyIndex];
    if (!k) continue;
    dict[String(k)] = (row[langIndex] != null) ? String(row[langIndex]) : "";
  }

  var payload = { lang: lang, dict: dict, updated_at: new Date().toISOString() };

  return ContentService
    .createTextOutput(JSON.stringify(payload))
    .setMimeType(ContentService.MimeType.JSON);
}

STEP3 Studio側で翻訳対象にIDを設定する 🏷

Studioでは任意のdata属性を追加できないため、IDを翻訳キーとして使用します。

設定方法

Studio → 要素選択 → 設定 → タグ・属性 → ID入力

例:hero_titlecta_startnav_home

スプレッドシートのkeyと完全一致させる必要があります。

STEP4 カスタムコードを設置する 💻

サイト設定 → カスタムコード → body末尾に設置します。

<script type="module">
(async () => {
  const gasUrl = "GASのURL";
  const supported = ["ja", "en", "zh"];
  const cacheKeyPrefix = "i18n_cache_";
  const cacheTtlMs = 24 * 60 * 60 * 1000;

  const qs = new URLSearchParams(location.search);
  const rawLang = qs.get("lang");
  const urlLang = supported.includes(rawLang) ? rawLang : "ja";

  document.documentElement.setAttribute("lang", urlLang);

  function setActive(target) {
    const pairs = [
      ["lang_ja", "ja"],
      ["lang_en", "en"],
      ["lang_zh", "zh"],
      ["lang_ja_sp", "ja"],
      ["lang_en_sp", "en"],
      ["lang_zh_sp", "zh"]
    ];

    pairs.forEach(([id, code]) => {
      const el = document.getElementById(id);
      if (!el) return;
      if (code === target) el.setAttribute("aria-current", "true");
      else el.removeAttribute("aria-current");
    });
  }

  function buildUrl(target) {
    const u = new URL(location.href);
    if (target === "ja") u.searchParams.delete("lang");
    else u.searchParams.set("lang", target);
    return u.pathname + "?" + u.searchParams.toString() + u.hash;
  }

  function bind(id, target) {
    const el = document.getElementById(id);
    if (!el) return;

    el.addEventListener("click", (e) => {
      e.preventDefault();

      setActive(target);
      sessionStorage.setItem("pending_lang", target);

      location.href = buildUrl(target);
    });
  }

  setActive(urlLang);

  const pending = sessionStorage.getItem("pending_lang");
  if (pending && supported.includes(pending)) {
    setActive(pending);
    sessionStorage.removeItem("pending_lang");
  }

  bind("lang_ja", "ja");
  bind("lang_en", "en");
  bind("lang_zh", "zh");
  bind("lang_ja_sp", "ja");
  bind("lang_en_sp", "en");
  bind("lang_zh_sp", "zh");

  const cacheKey = cacheKeyPrefix + urlLang;

  function apply(dict) {
    Object.keys(dict).forEach((key) => {
      const el = document.getElementById(key);
      if (el) el.textContent = dict[key];
    });
  }

  let cached = null;
  try {
    cached = JSON.parse(localStorage.getItem(cacheKey));
  } catch (e) {}

  if (cached && cached.dict) {
    apply(cached.dict);
  }

  const isFresh = cached && cached.t && (Date.now() - cached.t) < cacheTtlMs;

  if (!isFresh) {
    try {
      const res = await fetch(gasUrl + "?lang=" + urlLang, { cache: "force-cache" });
      const json = await res.json();
      const dict = json.dict || {};

      if (!cached || JSON.stringify(cached.dict) !== JSON.stringify(dict)) {
        apply(dict);
        localStorage.setItem(cacheKey, JSON.stringify({
          dict,
          t: Date.now()
        }));
      }
    } catch (e) {
      console.error("i18n fetch error:", e);
    }
  }
})();
</script>

STEP5 言語切替ボタンを作成する 🔁

Studioで言語ボタンを配置します。JA / EN / 中文

それぞれのID:lang_jalang_enlang_zh

言語はURLクエリで制御します。例:?lang=en

この構成のメリット ✅

  • 翻訳修正はスプレッドシートのみ
  • CMSページにも対応可能
  • Studio側の修正が最小限
  • ノーコードのまま拡張できる
  • 運用コストを大幅削減できる

まとめ

Studioでも設計次第で、実用レベルの多言語サイトは十分に構築できます。スプレッドシート×GAS×ID差し替え方式はノーコード制作の自由度と運用性を両立できる現実的な解決策です。まずはクエリ方式で運用を安定させ、必要に応じてSEO対応構成へ発展させるとよいでしょう。

Contact

まずは、あなたの「なんだかんだ」を聞かせてください。

ご相談・ご依頼はフォームよりお気軽にご連絡ください。お見積もりまで費用は一切かかりません。

お問い合わせフォームへオンライン面談に全国対応しています。