mcpField
L
localise

localise

github.com/morphet81開発083 回インストール25 週間前に更新
リポジトリ

localise について

英語テキストから、コピー機能付きのLokalise向けインタラクティブHTML翻訳ページを生成するスキルです。単数・複数の入力に対応し、翻訳内の補間変数を保持します。

主な機能

  1. 01翻訳HTMLページの生成
  2. 02単数形と複数形への対応
  3. 03補間変数の保持
  4. 04翻訳文のコピー
  5. 05対応するMarkdown表の作成

活用シーン

  1. 01Lokalise用のアプリ文言の準備
  2. 02複数言語の翻訳確認
  3. 03翻訳文のローカライズワークフローへのコピー

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/morphet81/cheat-sheets --skill localise

インストール後、Claude Code で/localiseを入力して読み込まれたか確認します。

詳細

Lokalise 翻訳ジェネレーター

Lokalise に翻訳を貼り付けるための、インタラクティブな HTML 翻訳ページを生成します。

使用する場面

  • ユーザーが英語の文字列(複数形を含む場合と含まない場合があります)を提示し、Lokalise 用の翻訳を求めている
  • ユーザーがアプリの対応言語へのキーの翻訳について言及している
  • ユーザーがクリップボードにコピーできる、すぐに使える翻訳リファレンスを必要としている

入力

$ARGUMENTS を翻訳対象の英語テキストとして解析します。形式は <英語の単数形> [| <英語の複数形>] です。

  • $ARGUMENTS に区切り文字 | が含まれる場合は、単数形(| の前)と複数形(| の後)に分割します
  • $ARGUMENTS に | が含まれない場合は、文字列全体をすべての言語の単数形(other)として扱います
  • $ARGUMENTS が空の場合は、AskUserQuestion を使って英語のテキストをユーザーに尋ねます

ユーザーは次の情報も指定できます。

  1. キー名(任意):例:tables::selected_count。指定されていない場合は、英語の文字列から導出します。
  2. 変数:文字列には %{variable_name} 形式の補間トークンが含まれる場合があります。すべての翻訳で、これらをそのまま保持してください。

対象言語(この順序を厳守)

#コード言語複数形(Lokalise)RTL
1en英語one, otherいいえ
2arアラビア語zero, one, two, few, many, otherはい
3zh-CN中国語(簡体字)otherいいえ
4zh-TW中国語(繁体字)otherいいえ
5nlオランダ語one, otherいいえ
6frフランス語one, otherいいえ
7deドイツ語one, otherいいえ
8heヘブライ語one, otherはい
9hiヒンディー語one, otherいいえ
10idインドネシア語otherいいえ
11itイタリア語one, otherいいえ
12ja日本語otherいいえ
13kmクメール語otherいいえ
14ko韓国語otherいいえ
15loラオス語otherいいえ
16msマレー語otherいいえ
17ptポルトガル語one, otherいいえ
18ruロシア語one, few, many, otherいいえ
19esスペイン語one, otherいいえ
20tlタガログ語zero, one, two, few, many, otherいいえ
21thタイ語otherいいえ
22trトルコ語one, otherいいえ
23viベトナム語otherいいえ

翻訳ガイドライン

  • すべての翻訳で、%{...} 補間変数をそのまま保持してください。
  • other のみの言語では、単数・複数を区別せず、翻訳を1つだけ指定してください。
  • one/other の言語では、文法上適切な場合、単数形と複数形を指定してください。言語によって名詞が変化しない場合(例:ヒンディー語、一部の語におけるトルコ語)は、同じ形でもかまいません。
  • ロシア語(one/few/many/other)では、ロシア語の複数形の格変化規則に従ってください。
  • アラビア語(zero/one/two/few/many/other)では、アラビア語の複数形規則に従ってください。自然な表現になる場合は、zero 形で個数変数を省略してもかまいません(例:「項目が選択されていません」)。
  • タガログ語(zero/one/two/few/many/other)では、タガログ語のリンカー規則に従ってください。自然な表現になる場合は、zero 形で個数変数を省略してもかまいません。
  • RTL 言語(アラビア語、ヘブライ語)の翻訳行には、rtl CSS クラスを付けてください。
  • レストラン・ホスピタリティ向け UI(TableCheck 製品)にふさわしい、自然な翻訳にしてください。

出力

自己完結型の HTML ファイルを1つ生成します。

ファイルの保存場所

ファイルを次の場所に保存してください:{working_directory}/.tmp/translations-{sanitized_key}.html

{sanitized_key} は、キー名(またはキー名から作成したスラッグ)で、特殊文字をハイフンに置き換えたものです。

生成後、既定のシステムブラウザーでファイルを開いてください:

# macOS
open "{filepath}"
# Linux
xdg-open "{filepath}"
# Try open first, fall back to xdg-open
open "{filepath}" 2>/dev/null || xdg-open "{filepath}"
HTML 構造

生成する HTML は、次の構造に正確に従う必要があります。動的な内容(キー名、翻訳)のみを変更し、以下のテンプレートをそのままコピーしてください。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{KEY_NAME} — Plural Translations</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
  :root {
    --bg: #0e1117;
    --surface: #161b22;
    --surface-2: #1c2129;
    --border: #2d333b;
    --border-light: #373e47;
    --text: #e6edf3;
    --text-muted: #8b949e;
    --accent: #58a6ff;
    --accent-dim: #1a3a5c;
    --green: #3fb950;
    --green-dim: #1a3524;
    --yellow: #d29922;
    --yellow-dim: #3d2e00;
    --purple: #bc8cff;
    --purple-dim: #2a1a4e;
    --orange: #f0883e;
    --red: #f85149;
    --code-bg: #1a1f27;
  }

  * { margin: 0; padding: 0; box-sizing: border-box; }

  body {
    background: var(--bg);
    color: var(--text);
    font-family: 'DM Sans', sans-serif;
    padding: 40px 32px;
    line-height: 1.6;
  }

  .container {
    max-width: 1360px;
    margin: 0 auto;
  }

  header { margin-bottom: 36px; }

  h1 {
    font-size: 22px;
    font-weight: 700;
    color: var(--text);
    margin-bottom: 6px;
    display: flex;
    align-items: center;
    gap: 10px;
  }

  h1 code {
    font-family: 'JetBrains Mono', monospace;
    font-size: 16px;
    background: var(--accent-dim);
    color: var(--accent);
    padding: 3px 10px;
    border-radius: 6px;
    font-weight: 500;
  }

  .subtitle { color: var(--text-muted); font-size: 14px; }

  .legend { display: flex; gap: 20px; margin-top: 14px; flex-wrap: wrap; }
  .legend-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-muted); }
  .legend-dot { width: 10px; height: 10px; border-radius: 3px; }
  .legend-dot.one { background: var(--green); }
  .legend-dot.other { background: var(--accent); }
  .legend-dot.few { background: var(--yellow); }
  .legend-dot.many { background: var(--purple); }
  .legend-dot.two { background: var(--orange); }
  .legend-dot.zero { background: var(--red); }

  table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow: hidden;
    font-size: 14px;
  }

  thead th {
    background: var(--surface-2);
    color: var(--text-muted);
    font-weight: 600;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.8px;
    padding: 12px 16px;
    text-align: left;
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 2;
  }

  thead th:first-child { width: 50px; }
  thead th:nth-child(2) { width: 140px; }
  thead th:nth-child(3) { width: 100px; }

  tbody tr { transition: background 0.15s; }
  tbody tr:hover { background: var(--surface); }
  tbody tr:not(:last-child) td { border-bottom: 1px solid var(--border); }
  td { padding: 10px 16px; vertical-align: top; }

  .lang-code { font-family: 'JetBrains Mono', monospace; font-size: 13px; font-weight: 500; color: var(--accent); }
  .lang-name { font-weight: 500; color: var(--text); font-size: 13px; }
  .lang-name span { color: var(--text-muted); font-weight: 400; font-size: 12px; display: block; }

  .form-tag {
    display: inline-block;
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    font-weight: 500;
    padding: 2px 8px;
    border-radius: 4px;
    min-width: 46px;
    text-align: center;
    flex-shrink: 0;
  }

  .form-tag.one { background: var(--green-dim); color: var(--green); }
  .form-tag.other { background: var(--accent-dim); color: var(--accent); }
  .form-tag.few { background: var(--yellow-dim); color: var(--yellow); }
  .form-tag.many { background: var(--purple-dim); color: var(--purple); }
  .form-tag.two { background: #3d1f00; color: var(--orange); }
  .form-tag.zero { background: #3d1116; color: var(--red); }

  .translation-cell { display: flex; flex-direction: column; gap: 6px; }

  .translation-row {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .translation-text {
    font-family: 'JetBrains Mono', monospace;
    font-size: 13px;
    color: var(--text);
    flex: 1;
  }

  .translation-text .var { color: var(--yellow); }

  .copy-btn {
    flex-shrink: 0;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text-muted);
    font-family: 'DM Sans', sans-serif;
    font-size: 11px;
    font-weight: 500;
    padding: 4px 10px;
    border-radius: 5px;
    cursor: pointer;
    transition: all 0.15s;
    display: flex;
    align-items: center;
    gap: 4px;
    white-space: nowrap;
  }

  .copy-btn:hover {
    background: var(--border);
    color: var(--text);
    border-color: var(--border-light);
  }

  .copy-btn:active { transform: scale(0.96); }

  .copy-btn.copied {
    background: var(--green-dim);
    border-color: var(--green);
    color: var(--green);
  }

  .copy-btn svg { width: 13px; height: 13px; }

  .translation-row.handled {
    background: rgba(248, 81, 73, 0.2);
    border-radius: 4px;
    padding: 2px 6px;
    margin: -2px -6px;
  }

  .rtl .translation-text { direction: rtl; text-align: right; }

  footer {
    margin-top: 24px;
    padding: 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.8;
  }

  footer strong { color: var(--text); font-weight: 600; }
  footer code {
    font-family: 'JetBrains Mono', monospace;
    background: var(--code-bg);
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 11px;
  }

  .toast {
    position: fixed;
    bottom: 24px;
    right: 24px;
    background: var(--green-dim);
    border: 1px solid var(--green);
    color: var(--green);
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    font-weight: 500;
    padding: 10px 18px;
    border-radius: 8px;
    opacity: 0;
    transform: translateY(10px);
    transition: all 0.25s ease;
    pointer-events: none;
    z-index: 100;
    display: flex;
    align-items: center;
    gap: 6px;
  }

  .toast.show { opacity: 1; transform: translateY(0); }
</style>
</head>
<body>
<div class="container">
  <header>
    <h1>Translations for <code>{KEY_NAME}</code></h1>
    <p class="subtitle">23 languages · CLDR plural rules · Variable: <code style="font-family:'JetBrains Mono',monospace;background:var(--yellow-dim);color:var(--yellow);padding:1px 6px;border-radius:4px;font-size:13px">%{count}</code></p>
    <div class="legend">
      <div class="legend-item"><div class="legend-dot one"></div> one</div>
      <div class="legend-item"><div class="legend-dot other"></div> other</div>
      <div class="legend-item"><div class="legend-dot few"></div> few</div>
      <div class="legend-item"><div class="legend-dot many"></div> many</div>
      <div class="legend-item"><div class="legend-dot two"></div> two</div>
      <div class="legend-item"><div class="legend-dot zero"></div> zero</div>
    </div>
  </header>

  <table>
    <thead>
      <tr>
        <th>#</th>
        <th>Language</th>
        <th>Forms</th>
        <th>Translations</th>
      </tr>
    </thead>
    <tbody>
      
    </tbody>
  </table>

  <footer>
    <strong>Notes:</strong><br>
    • These translations should be reviewed by native speakers before production use.<br>
    • Plural forms follow CLDR plural rules as configured in Lokalise.<br>
    • RTL languages (Arabic, Hebrew) are displayed right-to-left.
  </footer>
</div>

<div class="toast" id="toast">
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
  <span id="toast-text">Copied!</span>
</div>

<script>
  const COPY_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>';
  const CHECK_ICON = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" width="13" height="13"><polyline points="20 6 9 17 4 12"/></svg>';
  let toastTimeout;

  function copyText(btn) {
    const row = btn.closest('.translation-row');
    const textEl = row.querySelector('.translation-text');
    const text = textEl.getAttribute('data-copy');

    navigator.clipboard.writeText(text).then(() => {
      showFeedback(btn, text);
    }).catch(() => {
      const ta = document.createElement('textarea');
      ta.value = text;
      ta.style.cssText = 'position:fixed;opacity:0';
      document.body.appendChild(ta);
      ta.select();
      document.execCommand('copy');
      document.body.removeChild(ta);
      showFeedback(btn, text);
    });
  }

  function showFeedback(btn, text) {
    const row = btn.closest('.translation-row');
    row.classList.add('handled');

    btn.classList.add('copied');
    btn.innerHTML = CHECK_ICON + 'Copied!';
    setTimeout(() => {
      btn.classList.remove('copied');
      btn.innerHTML = COPY_ICON + 'Copy';
    }, 1500);

    const toast = document.getElementById('toast');
    const toastText = document.getElementById('toast-text');
    const display = text.length > 45 ? text.substring(0, 45) + '…' : text;
    toastText.textContent = 'Copied: ' + display;
    clearTimeout(toastTimeout);
    toast.classList.add('show');
    toastTimeout = setTimeout(() => toast.classList.remove('show'), 2000);
  }
</script>
</body>
</html>

行テンプレート

各言語の行を作成するには、以下のテンプレートを使用してください。{N}、{LANG_NAME}、{LANG_CODE}、翻訳文を置き換えてください。

コピー用ボタンの HTML(全箇所で再利用):

<button class="copy-btn" onclick="copyText(this)"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>Copy</button>
単一形(other のみ)

対象:zh-CN、zh-TW、id、ja、km、ko、lo、ms、th、vi

<tr>
  <td><span class="lang-code">{N}</span></td>
  <td><span class="lang-name">{LANG_NAME}<span>{LANG_CODE}</span></span></td>
  <td><span class="form-tag other">other</span></td>
  <td class="translation-cell">
    <div class="translation-row">
      <span class="translation-text" data-copy="{PLAIN_TEXT}">{DISPLAY_HTML}</span>
      {COPY_BUTTON}
    </div>
  </td>
</tr>
2つの形(one/other)

対象:en、nl、fr、de、he、hi、it、pt、es、tr

<tr>
  <td><span class="lang-code">{N}</span></td>
  <td><span class="lang-name">{LANG_NAME}<span>{LANG_CODE}</span></span></td>
  <td><span class="form-tag one">one</span> <span class="form-tag other">other</span></td>
  <td class="translation-cell">
    <div class="translation-row{RTL_CLASS}">
      <span class="form-tag one">one</span>
      <span class="translation-text" data-copy="{PLAIN_ONE}">{DISPLAY_ONE}</span>
      {COPY_BUTTON}
    </div>
    <div class="translation-row{RTL_CLASS}">
      <span class="form-tag other">other</span>
      <span class="translation-text" data-copy="{PLAIN_OTHER}">{DISPLAY_OTHER}</span>
      {COPY_BUTTON}
    </div>
  </td>
</tr>
4つの形(one/few/many/other)

対象:ru

<tr>
  <td><span class="lang-code">{N}</span></td>
  <td><span class="lang-name">Russian<span>ru</span></span></td>
  <td><span class="form-tag one">one</span> <span class="form-tag few">few</span> <span class="form-tag many">many</span> <span class="form-tag other">other</span></td>
  <td class="translation-cell">
    <div class="translation-row">
      <span class="form-tag one">one</span>
      <span class="translation-text" data-copy="{PLAIN}">{DISPLAY}</span>
      {COPY_BUTTON}
    </div>
    <div class="translation-row">
      <span class="form-tag few">few</span>
      <span class="translation-text" data-copy="{PLAIN}">{DISPLAY}</span>
      {COPY_BUTTON}
    </div>
    <div class="translation-row">
      <span class="form-tag many">many</span>
      <span class="translation-text" data-copy="{PLAIN}">{DISPLAY}</span>
      {COPY_BUTTON}
    </div>
    <div class="translation-row">
      <span class="form-tag other">other</span>
      <span class="translation-text" data-copy="{PLAIN}">{DISPLAY}</span>
      {COPY_BUTTON}
    </div>
  </td>
</tr>
6つの形(zero/one/two/few/many/other)

対象:ar、tl

<tr>
  <td><span class="lang-code">{N}</span></td>
  <td><span class="lang-name">{LANG_NAME}<span>{LANG_CODE}</span></span></td>
  <td><span class="form-tag zero">zero</span> <span class="form-tag one">one</span> <span class="form-tag two">two</span> <span class="form-tag few">few</span> <span class="form-tag many">many</span> <span class="form-tag other">other</span></td>
  <td class="translation-cell">
    
    
    <div class="translation-row{RTL_CLASS}">
      <span class="form-tag zero">zero</span>
      <span class="translation-text" data-copy="{PLAIN}">{DISPLAY}</span>
      {COPY_BUTTON}
    </div>
    
  </td>
</tr>

表示 HTML の書式

{DISPLAY} の内容では、%{variable} トークンを黄色のハイライト用 span で囲んでください。

  • プレーンテキスト(data-copy 用):%{count} tables selected
  • 表示 HTML(表示内容用):<span class="var">%{count}</span> tables selected

Markdown ファイル

HTML ファイルに加えて、すべての翻訳を表形式でまとめた Markdown ファイルも生成してください。

ファイルの保存場所

ファイルを次の場所に保存してください:{working_directory}/.tmp/translations-{sanitized_key}.md

(HTML ファイルと同じディレクトリ、同じファイル名で、拡張子のみ .md にします。)

Markdown の構造

ファイルは次の構造に正確に従う必要があります。

# Translations: `{KEY_NAME}`

| # | Language | Code | Form | Translation |
|---|----------|------|------|-------------|
| 1 | English | en | one | %{count} table selected |
| 1 | English | en | other | %{count} tables selected |
| 2 | Arabic | ar | zero | ... |
| 2 | Arabic | ar | one | ... |
| 2 | Arabic | ar | two | ... |
| 2 | Arabic | ar | few | ... |
| 2 | Arabic | ar | many | ... |
| 2 | Arabic | ar | other | ... |
| 3 | Chinese (Simplified) | zh-CN | other | ... |
...

ルール:

  • 言語は HTML と同じ順序(1~23)で並べてください。
  • 複数形の各形をそれぞれ別の行にしてください。
  • # 列には、同じ言語のすべての形で同じ行番号を使用してください(例:アラビア語の行はすべて 2)。
  • Translation 列にはプレーンテキストを記載してください(HTML マークアップを使わず、%{...} 変数はそのまま保持します)。
  • 単一形(other のみ)の言語は1行にしてください。
  • 複数の形がある言語は、各形を次の順序で個別の行にしてください:zero、one、two、few、many、other(その言語に該当する形のみ)。

保存前のチェックリスト

  1. 指定された正確な順序ですべての23言語が含まれていること
  2. 言語ごとの正しい複数形が使われていること(汎用 CLDR ではなく、上記の Lokalise 形式一覧に従う)
  3. すべての翻訳で %{...} 変数がそのまま保持されていること
  4. data-copy 属性にプレーンテキストが含まれていること(HTML を含めない)
  5. 表示内容で、変数が <span class="var"> で囲まれていること
  6. アラビア語とヘブライ語の行に RTL クラスが適用されていること
  7. 行番号が1~23の連番になっていること
  8. 翻訳のすべての行にコピー用ボタンがあること
  9. HTML ファイルと Markdown ファイルの両方が .tmp/ フォルダーに保存されていること
  10. HTML ファイルが生成後に既定のブラウザーで開かれていること

コメント