WordPress プラグインやテーマの翻訳でうまく手を抜く(いい意味で)

WordCamp Kansai 2014 に行ってきました。2日め“コントリビューターデイ”、プラグイン・テーマ翻訳の世話役だったのですが、可搬 PC は持っていないし、子連れだし、遠方まで帰るために途中で抜けなければならないし、さらに、「Mac/Win で Poedit というアプリケーションを使う」というのが最も一般的と思われるのに自分では使っていないため ((ふだんは Debian 上の Emacs の po-mode で作業しています。))に操作方法を即答できない……、という幾重もの役立たずぶりですみませんでした。こどもの相手やら何やら、こちらのほうがお世話になりっぱなしで、ありがとうございました。

そういう中で質問を受けたことを、今さらながらここに書いておこうと思います。

翻訳作業のステップ

WordPress のプラグインやテーマの翻訳をやってみようという記事はあちこちにたくさんあります。ここでは細かく書きませんので、それらを参照してみてください。「POT ファイルとは何か」「PO ファイルとは何か」「それらはどこにあるか」などは既に知っているという前提で進めます。

おさらいです。WordPress のプラグインやテーマの翻訳作業のステップは

  1. プラグインやテーマのプログラムの中の翻訳されるべきメッセージに __() や _e() などのマークを付ける
  2. マークされた文字列を抽出して POT ファイルと呼ばれる、翻訳者にとって原本となるものを作成する
  3. POT ファイルを元に、メッセージをそれぞれの言語に翻訳した PO ファイル を準備する
  4. PO ファイルを編集する (これがほんとうの翻訳作業)

です。作業のスタート地点が後ろに近いほど、とっかかりやすいです ((このあと、それを開発者に送るとか、開発者の側では送られてきたものを最新版に合わせてからパッケージに同梱するとかの作業もありますが、ここでは省略します。それらとステップ2については以前「プラグインやテーマの国際化を少し楽に」に書きました。))。

最も始めやすい状態: ステップ4から

たくさんある記事のひとつ、Nao さんの「2014年版: WordPress プラグイン・テーマの翻訳を始めてみよう」を見てみます。

その記事にありますように、最も手軽に始められるのが、既に全部または一部翻訳がなされているものに対して、誤訳を修正するとか、別の訳語にするとか、訳の抜けている部分を補う、というものです。これなら最初のハードルがぐっと低く、ともかく「やってみよう」という気になれます。

Poedit なら、書き換えたい PO ファイルを開き、当該箇所を修正・加筆するだけです。

その次に楽な状態: ステップ3から

プラグインやテーマそのものは翻訳可能 (POT ファイルが用意されている) だが日本語訳 (name-ja.po) がない状態というのが、その次にとっつきやすい状態です。

公式ディレクトリに登録されているプラグインテーマなら「translation-ready」というタグが付けられているでしょう。ここでいうステップ1や2の処理が既にされているという意味です。

Poedit なら、「ファイル」-「POT ファイルを元に新しいカタログを作成…」で、「言語」に ja を指定して適切な名前 (name-ja.po の形) で保存します。

コマンドラインを使えるなら Poedit を使わずに、

msginit -i name.pot -o name-ja.po -l ja 

です。意味はなんとなくわかりますね。

この時点で、翻訳率0% の日本語翻訳ファイル name-ja.po ができます。

ステップ3をステップ4に

「0%」……嫌な響きですね。これだけでやる気が削がれてしまいます。なので、過去の資産から使えるものは少しでも流用します。

たとえばテーマの翻訳をしようとしているとします。その最初に、既存の、たとえばデフォルトテーマの twentyfourteen の翻訳を取り込んでしまおうというのです。

もしステップ3をコマンドラインでできたようなら、これまたコマンドラインで

msgmerge -o name-ja.po -C wordpress/wp-content/languages/themes/twentyfourteen-ja.po name-ja.po name.pot

のように、msgmerge を使います。-C で参考とする PO ファイルを指定します。-C はひとつのコマンドラインの中に何度でも指定できるので、WordPress 本体の ja.po や admin-ja.po も追加するといいかもしれません。

Poedit ではこれに相当する操作が簡単にできないようです。そこでステップ3の代わりに、次のようにします。name-ja.po がまだ存在しない状態で、参考とする PO ファイル (たとえば twentyfourteen-ja.po) を name-ja.po という名前でコピーします。これを Poedit で開き、「カタログ」-「POTファイルでカタログを更新…」します。

すると、英文が合致する分の翻訳がそのまま取り込まれます ((合致しなかった部分を掃除するには Poedit では「カタログ」-「Purge Deleted Translations」です。))。プラグインでは参考にする似たものを見つけてくることが難しいかもしれませんが、テーマの場合は、デフォルトのテーマを参考にしてうまくいけば80%ほども翻訳済みにしてしまうことができます。

これで、スタート地点をステップ3からではなく、ステップ4からにすることができます。

翻訳メモリ

Poedit には翻訳メモリという機能があります。データベースに登録しておけば、それを自動的に参照して、英文が合致する分を埋めてくれます。まずは WordPress 本体の ja.mo や admin-ja.mo それにデフォルトのテーマの twentyfourteen-ja.mo を登録しておきましょう。

これによってもスタート地点をステップ3からではなく、ステップ4からにすることができます。

前節の方法と翻訳メモリの方法は同時に使うこともできますので、積極的に翻訳メモリを使うのがいいでしょう。

といっても私自身が Poedit 自体(ということは翻訳メモリも)使っていませんので詳しく書けません。かなり古い記事ですが Tai さんの「poEditの翻訳メモリ機能を使う」や Miyoshi さんの「poEdit で翻訳ファイルを作る 」の「翻訳メモリを活用する」の節などを参考にしてください。

手抜きの効果

「手抜き」というと負のイメージの言葉ですが、ここではまったくそういうことはありません。むしろ用語の統一という点でも、積極的にここに書いた方法をとるべきだと思います。

そこで、最初掲げたステップを修正して、

  1. プラグインやテーマのプログラムの中の翻訳されるべきメッセージに __() や _e() などのマークを付けておく
  2. マークされた文字列を抽出して POT ファイルと呼ばれる、翻訳者にとって原本となるものを作成
  3. POT ファイルを元に、メッセージをそれぞれの言語に翻訳した PO ファイル を作る
    1. 過去の資産を参照して自動的に、できるだけ翻訳を埋める
  4. PO ファイルを編集する (これがほんとうの翻訳作業)

の赤い字の項目を必ず実行するように意識することを強くお奨めします。

ざっと検索してみた Poedit の使い方、WordPress の翻訳や WordPress 翻訳祭りのような WordBench などでの解説でも「POT ファイルから PO ファイルを作りましょう。空っぽの ja.po ができましたね。さあ翻訳を始めましょう」と、このあいだのステップが飛ばされているように思います。

いまからやろうとしている翻訳は、単語レベルでは既に誰かがやっているかもしれません。WordCamp Kansai 2014 のキーワードは「Share 分かちあい」でしたね。share できるものは share して、抜ける手はなるべく抜いて、その余力は別のところで活かしましょう。

これくらいの下調べは前もってやっておくべきでした。すみません。今後の各地のイベントや、あるいは個人で、翻訳やってみようかなというときには、前に書いた「WordPress 翻訳祭り—今さら注意してもらえない「日本語」について 」と併せて参考にしてもらえればと思います。

Mew のサマリに表示される本文の部分が変わった

Web のフォームによって送られる次のような書式のメールをしょっちゅう受け取ります。冒頭から

[氏名] ...
[よみかな] ...
[郵便番号] ...
[住所] ...
     ... 

のように、 [ ] ではじまる行があります(「氏名」や「住所」というのはあくまで例です)。

メールリーダーには Mew を使っているのですが、そのサマリ表示に上記の部分がばっさりカットされて、どうでもいいところからの本文の一部が現れるようになりました。

さて検索してみると、“[” ではじまる行を引用部分とみなし無視する、という変更が行われたようです。自分の手元でこのような変化がつい最近起こったのは Debian のパッケージの更新の時期によるものでしょう。

この部分(mew-scan.el の mew-regex-ignore-scan-body-list 定義部分)を元に戻しながら、~/.mew.el に setq

(setq mew-regex-ignore-scan-body-list
  '("^[ \t]*$"
    "^[ \t]*[-a-zA-Z0-9]+: "
;;    "^[ \t]*[[>:|#;/_}]" ;; https://github.com/kazu-yamamoto/Mew/commit/98d4fd7be3216792824e2c737006921b3b49b4b0 で加えられた変更
    "^[ \t]*[>:|#;/_}]" ;; を戻す。すなわち、"[" で始まる行を引用とはみなさない
    "^[ \t]*\\w+\\(['._-]+\\w+\\)*>"
    "^[ \t]*[[</(.-]+ *\\(snip\\|\\.\\.\\)"
    "^   "
    "^--"
    "^- --"
    "^=2D"
    "^.\\{1,100\\}\\(:\\|;\\|/\\)[ \t]*$"
    "^.\\{1,100\\}\\(wrote\\|writes?\\|said\\|says?\\)[^.!\n]?[ \t]*$"
    "^[ \t]*\\(On\\|At\\) .*[^.! \t\n][ \t]*$"
    "^[ \t]*In \\(message\\|article\\|mail\\|news\\|<\\|\"\\|\\[\\|(\\)"))

と書くことで、以前の状態にすることができました。

トイレの明かりが消えない……えっ?

スイッチを OFF にしてもトイレの照明が消えない。ON にすると正常に点灯し、OFF にすると0.5秒間隔ほどで点滅する。以前のことを思い出し、ありゃまたLED電球がおかしくなってしまったか、案外寿命は短いな、買いに行かなけりゃなどと考えながら部屋に戻った。

が、しばらくして、「はて、よく考えるとスイッチが OFF なのだから、電球が壊れたとしてもそもそも点滅するのは変なのでは?」と思い至る。だとすると、スイッチが壊れたのか。もう一度トイレに戻って何度かパチパチしてみても状況は変わらない。うーむ。

この家の配線はほとんどむき出しなので線を追える。スイッチの上方、トイレの扉の上に黒くて丸いジョイントボックス(明工社 ジョイントボックス 小 20A 300V MJ2420こんなやつ)がある。

ふとその蓋をくるくると外してみると……なんとムカデが!! とうぜん感電死していたのだが、絶妙のポジションでブレーカーを落とすことなくスイッチをショートカットしていたのか。

2,3日前は寝床の真上の天井にさかさまに張り付いているムカデを発見したし、その数日前には、向こうの部屋で何やら猫が暴れてるなと思って見に行ったらヘビと戦っているし。これだから田舎の家は……。

DoSPOT 設置をあきらめる

ずっとデスクトップ PC の前に座っている生活なので無線 LAN はあまり考えていませんでしたが、最近 Nexus7 を手に入れたので、これまた数年前に入手していた無線 LAN ルーター WN-G300DGR を置いて使ってみていました。まあ特に支障はありません。

そこへ「DoSPOT」の営業の電話がかかってきました。DoSPOT というのは、客側から見ると、時間・回数制限付きの公衆無線アクセスポイントということになります。また、「フレッツ・スポット」のユーザーなら制限なしに利用できます。設置側としては、「Wi-Fi 使えます」と言えますし、「フレッツ・スポット」提供エリアとしてそのページに掲載されるという宣伝効果? が期待できます。またオーナー側に SSID (一般客には公開しない) があり、既存の無線 LAN ルーターに置き換えることができるかなと思えました。月額500円(税抜)ですが、1年間は無料というのでとりあえず OK しました。

LAN 環境

ところで現在の LAN 環境は、LAN 内部に公開サーバーを置いていたり、ネットワーク接続のプリンターがあったりという、単に外につなげればいいというだけではなくそもそも単純ではない状態です。したがって内部向けの DNS サーバーが存在し、これを参照するようにしないと自分のところの Web を内部から見ることができません。

DoSPOT ルーター

しばらくして、担当者が DoSPOT ルーターを持って「工事」にやってきました。が、設置場所の問題だの既存の無線 LAN ルーターを外したりだのややこしかったので、「設置はこちらでやるから」と言って機械だけ置いていってもらいました。DoSPOT ルーターは NEC 製 の MW-3301-R (PDF) というものでした。

さて自分で設置して設定しようとすると、MW-3301-R が上述の LAN 環境に対応できないことが判明しました。

有線 LAN ポートが足りない

まず MW-3301-R には有線 LAN ポートが2口しかありません。一方、既存の無線 LAN ルーターには3口あって、宅内にはそれを全部塞ぐだけの機器があります。増設ならともかく置き換えることはできません。すると今度は(設置場所に)電源の口が足りません。

DNSの設定ができない

MW-3301-R の設定は、それに接続した PC などのブラウザで Web 画面をとおして行います。と言っても設定を変更できるのは、オーナー向け SSID (デフォルトでは「DoSPOT-OWNER」)についてのみ。それについては DNS の設定もできるので、プライマリに内部向け DNS サーバー、セカンダリにゲートウェイ(プロバイダの DNS を代理している)を設定することで事なきを得ました。

ところが、客側が接続する SSID (「DoSPOT-FREE」や「NTTWEST-SPOT」)に関する設定は一切できないようです。DoSPOT カスタマーセンターに電話して聞いてみたところ、はじめは DNS について「オーナー向け設定と連動しているかも」との回答だったのですが、とてもそのような挙動には見えないので強くそのように言うと、数時間後に「再現テストしてみたところ連動しておらず、それらは一切設定変更できません」との回答がありました。

DoSPOT の売り文句

Point 3 店舗や施設の情報をお客様に見てもらえる

  • Wi-Fiを利用する際に店舗ホームページを表示できる
  • 店舗や施設のホームページを紹介

    お客様がDoSPOTを利用される際に店舗や施設のホームページを紹介します。

    同じことを客側から

    Point 3 店舗や施設の情報を確認できる

    • 店舗情報、クーポン、ブログなどをチェック。
    Wi-Fiを利用する際に店舗ホームページで情報をゲット!

    無料ログインの際に、店舗ホームページがある場合は表示されますので、店舗情報やクーポンのチェック、ブログなどが閲覧可能です。

    とあるのですが、これがまったく使えないということになります。

    そのほか残念なところ

    時刻の設定が、再起動のたびに元(1970年1月1日)に戻ってしまうようです。と言ってもログにもこの時刻は使われていません。何なんだろう。

    「DoDPOT-FREE」は暗号なし。うーん、そうなんだ……。

    結局使わないことに

    DoSPOT がまったくダメとは言いません。うちの環境に合わなかったというだけです。有線 LAN のポート数は事前に知ろうと思えば知ることはできました。それを見落としていたのはこちらの落ち度でした。DNS の設定については、実際に試してみるまでわかりませんでした。その手段がまったくないとは思っていませんでした。

    既存の無線 LAN ルーターかまたはそれよりちょっとだけましな、マルチ SSID のできる機器で、ひとつの SSID を自分で客用に設定してやればすむ話です。宣伝効果? は、FREESPOT マップ にでも登録すればいいかもしれません。そもそも Wi-Fi 環境うんぬんで客足に影響するような商売でもありませんし。いずれにせよ無料だからまだいいようなものの、月額料金、電気代(これは微々たるものか)を払って、こちらに何の得があるというのでしょう (いや、そういう形態の商売もあるでしょうが)。しばらく放置して、無料期間が終わるまでに解約することにしようと思います。やれやれ。

    WordPress 翻訳祭り—今さら注意してもらえない「日本語」について

    今週末、全国各地で WordPress 翻訳祭りが開催されるようです。WordPressの各言語版がどのような仕組みで実現されているか、とか、実際に翻訳作業をするアプリケーションの説明などが、あちこちに見られるようになりました。(【追記】このあと WordCamp Kansai 2014 コントリビューターデイもありますし、今後も参照されるかもしれないので若干手直ししました。)

    でも、もっとも根っこのところにある「日本語」については、日本語の話者ならもう今さら言うことはないという感じで、なかなか誰も注意してくれません。

    ふだん自分が書く日本語と違う点は、これが協調作業だということです。WordPress 本体と、テーマやプラグイン、Codex で、書き手によって文体や表現がバラバラだと、読み手に対していらぬストレスを与えることになります。ここは自分が気持ちよく書くことよりも、自分だけ外れた書き方になっていないか、に注意することが必要です。

    日本語スタイルガイド

    WordPress 本体の翻訳にあたっては、ガイドラインを定めています

    まず基本となる「日本語スタイルガイド」(簡易版の PDF) があって、そこに書かれているルールから外れる WordPress 日本語版独自のルールという形で決めています。翻訳祭りに参加される方は、ぜひ事前に目を通して、もちろん全部覚えておくことは難しいでしょうが、「あれ、どうだったっけ?」と引っかかる程度にはしておくといいでしょう。

    • 日本語の句点は全角の「。」を、読点は全角の「、」を使う。
    • 日本語には全角文字 (2 バイト文字) を使う。
    • 英数字、符号には半角文字 (1 バイト文字) を使う。(例外は句読点、鍵括弧、中黒。これらは全角文字を使う)
    • 数字は、慣習的に使われている場合を除いて、算用数字 (1、2、3) を使う。

    このあたりまでは、特に気をつけなくても大丈夫だと思います。

    以下、気をつけないと自分の癖が出てしまいそうなところを挙げてみます。

    文字間のスペース

    • 半角文字と全角文字の間には、半角文字 1 字分のスペースを入れる。ただし例外は
      • 半角文字の前後が『』 「 」 。、の場合は半角スペースを入れない。
      • 丸括弧 ( ) の外側には、全角文字がきても半角文字がきても半角文字 1 字分のスペースを入れる。
      • 丸括弧 ( ) の内側には、全角文字がきても半角文字がきてもスペースを入れない。
      • コロン : の前には半角スペースを入れない ((「日本語スタイルガイド」に明記はされていませんが、例文によるとこうなっています。))。
      • 半角数字の前後には半角スペースを入れない(日時など。例: 2009年5月10日12時30分48秒、1件のコメント、150ピクセル)

    です。これははじめに意識しておかないと、うっかり適当にやってしまいがちです。

    外来語カタカナ末尾の長音表記

    基本的には内閣告示第二号「外来語の表記」に従います。

    ざっくり言うと原則として、英語の語末が -er、-or、-ar のときは長音記号を付け、-y のときは長音記号を付けません。ただし例外も多くあります。

    漢字かな表記

    漢字にするかかな書きするかは

    • 原則として名詞と動詞には漢字を使い、接続詞、連体詞、助動詞、補助動詞、助詞、連語、形式名詞、接頭語、接尾語はかな書きにする。

    です。「日本語スタイルガイド」 (長いほうの PDF) の付録に一覧表があります。「してください」「すでに」「すべて」「だれも」などはかな書きです ((「すべて」「だれ」がかな書きなのは、この日本語スタイルガイドが作られた時点では常用漢字にそれらが含まれていなかったからだと思います。2010年の改定で「全て」の読み「すべて」、「誰」という漢字が含まれたので、今後はこれらは漢字書きでもいいかもしれません。しかしいま勝手にそう判断しても統一がとれませんので、全体の合意が形成されるまで当面はかな書きのままとしましょう。))。

    ここまで、WordPress 本体のガイドラインを紹介しました。テーマやプラグインもぜひこれに準拠してほしいと思います。

    Codex もほぼ準拠していると思いますが(どこかにガイドラインが示されていましたっけ?)、外れているものもけっこう見られます。括弧が全角になっていたり、和文-欧文間のスペースがあったりなかったり……。今回のような催しをきっかけにこのあたりのルールも整備されればいいなと思います。

    ところで、「用語」は、WordPress 本体やテーマ・プラグインを参照して、合わせる必要があります。WordPress 本体で見かけた語が Codex では別の訳語になっていた、ではたいへん困ります。手間ではありますが、すでにある訳語を探して、合わせましょう。どうしてもそれらが間違った訳と思える場合には、それぞれの作者・翻訳者、日本語版作成チームに連絡して、連携して全体をよくしていきましょう。

    それでは、Happy translating!

    Share the LOVE 分かちあい

    今年6月に開催予定の WordCamp Kansai 2014 のキーワードは「分かちあい」だそうです。

    WordCamp Kansai 2014のコピーにそっと入っている「Share the LOVE」の文字。これはWordPressのreadme.htmlにある一節で日本語版作成チームの方が「分かちあい」と訳してくださっています。(Makoさんが提案されたと聞いています)

    「分かちあい」。WordCamp Kansai 2014では、この分かちあいをテーマにしています。
    灯りをわけあうように知識を経験を、そしてこれからの未来をわかちあう。

    WordCamp Kansai 2014 開催します!

    ここに名前を挙げてもらって光栄に思うのと同時に、日本語版作成チームの皆さんの同意があってはじめてこうなっているのであって、私としては大いに照れているところです。とは言え、実は自分でも自分の案ということを何度か言ったことがあったのでした。

    この際なので、もっとじっくり掘り出してみました。

    まず大元の英語版の readme.html を見てみると、changeset 2338 で Share the Love が現れています。2005年2月のことです。これが日本語では、どういう経緯かわからないけれど「WordPress 愛用者の皆さんへ」と訳されていました。

    日本語版作成チームのメーリングリストを探してみると、2008年2月24日に、確かに私が「分かち合い」を提案していました ((なお、ここで署名に出てくる URL はすでに手放しており、現在表示されるのはまったく無関係です。それについては「迂濶にドメイン名を手放すのはよくない」に書きました。))。このときの変更点の一番下のあたりです。漢字かかな書きかはその後2回ほど変えて、現在の「分かちあい」にしました。

    いやあ、どんな変更があってどんな話をしていたかすっかりオープンな状態で、いつでも誰でも見られるんですね。オープンであること、自由であることが「WordPressってすごい」ところです。

    もう少しなにか気の利いたことを書けたらいいのでしょうが、WordCamp Kansai 2014 実行委員長の挨拶を読むと「WordPressってすごい」「分かちあい」に書かれていることにまったく同感なので、そちらをぜひ見てみてください。

    どこか自慢話のようになってしまったかもしれません。たかが一単語の日本語訳ですから、誰がやってもそう違いはありません。もし私がやらなくても誰かがやってくれたでしょう。でも逆に考えれば、たかがそのくらいを、たいして力のない私がやることができて、こうして WordCamp サイトオープンの挨拶で取り上げてもらえました。ああ自分じゃない誰かにいくらかでも何かを届けることができたんだな、と感じさせてもらえてとても幸せです。次は、これを目にしているあなたの番かもしれませんよ。「自分がやらなくても誰かがやってくれる」からほんの一歩だけでも踏み出してみませんか。

    ところで、share は、この界隈では「共有」という訳で広まっています。しかし私はどうもしっくりこないと感じています。ということをどこかに書いたことがあったのでした。「共有」だと「(他人と一緒ではあるけれど)自分も持つ」という意味合いが強いような気がして、それよりむしろ「配る、分け与える、ほかの人にも持たせる」というニュアンスを出せないものかと考えています。最近、Twitter も share に、というニュースも見ました。「共有」なんて訳語にならなきゃいいなと思っています。

    pandoc の使い方メモ — 相互参照について

    やりたいことは「元の文章を markdown で複数のファイルに分割して書き、それをウェブで公開するために個々に HTML に変換したい。もう一方では印刷できるような一括した PDF を LaTeX 経由で作りたい。ついでに EPUB も作りたい」です。割とありがちなケースだと思うので、もっとすっきりした方法があるように思うのですが、うまく見つけられませんでした。

    相互参照とは、HTML では id 属性と a タグで実現されるもの、LaTeX では \label{}\ref{} で表現されるものです。

    索引は、LaTeX では後で処理するために \index{} で印を付けておくものです。HTML と EPUB では使いません。

    例を挙げます。

    a.md
    
    はじめに {#hajimeni}
    ========
    
    ...
    
    用意するもの
    ============
    
    ...
    
    道具 {#dougu}
    ----
    
    * 包丁
    * まな板
    * ...
    
    これらは[「下ごしらえ」](b.html#shita)で使います。
    
    * 大きな鍋\index{おおきななべ@大きな鍋}
    * ...
    
    これらは[「調理」](b.html#chouri)で使います。
    
    材料 {#zairyo}
    ----
    
    ...
    
    
    b.md
    
    手順
    ====
    
    下ごしらえ {#shita}
    ----------
    
    ここで使う材料は[「材料」](a.html#zairyo)にまとめてあります。
    ...
    
    調理 {#chouri}
    ----
    
    ...
    大きな鍋\index{おおきななべ@大きな鍋}([「道具」](a.html#dougu)を参照のこと)を使います。
    ...
    
    盛り付け {#moritsuke}
    --------
    
    おわりに
    ========
    
    ...
    
    
    

    という文書が元になります。

    HTML

    a.md → a.html, b.md → b.html のように個々のページを独立して生成することにします。それを見越して、md ではリンクの書式のところにこれらのファイル名を入れておきます。

    md を pandoc

    pandoc -o a.html a.md
    pandoc -o b.html b.md
    

    と処理すると

    a.html
    <h1 id="hajimeni">はじめに</h1>
    <p>...</p>
    <h1 id="用意するもの">用意するもの</h1>
    <p>...</p>
    <h2 id="dougu">道具</h2>
    <ul>
    <li>包丁</li>
    <li>まな板</li>
    <li>...</li>
    </ul>
    <p>これらは<a href="b.html#shita">「下ごしらえ」</a>で使います。</p>
    <ul>
    <li>大きな鍋</li>
    <li>...</li>
    </ul>
    <p>これらは<a href="b.html#chouri">「調理」</a>で使います。</p>
    <h2 id="zairyo">材料</h2>
    <p>...</p>
    
    b.html
    <h1 id="手順">手順</h1>
    <h2 id="shita">下ごしらえ</h2>
    <p>ここで使う材料は<a href="a.html#zairyo">「材料」</a>にまとめてあります。 ...</p>
    <h2 id="chouri">調理</h2>
    <p>... 大きな鍋(<a href="a.html#dougu">「道具」</a>を参照のこと)を使います。 ...</p>
    <h2 id="moritsuke">盛り付け</h2>
    <h1 id="おわりに">おわりに</h1>
    <p>...</p>
    

    ができます。LaTeX の索引のために挿入しておいた \index{} は無視されるので、特に気にすることはありません。

    LaTeX 経由 PDF

    ソースは複数ファイルに分割されていても最終的な成果物はひとつであってほしいため、main.tex を用意しておき、

    main.tex
    \documentclass[a5paper]{jarticle}
    \usepackage[dvipdfmx]{hyperref}
    \usepackage{makeidx}
    \makeindex
    \begin{document}
    \tableofcontents
    %
    \input{a}
    \input{b}
    %
    \printindex
    \end{document}
    

    これから dvi を作り、さらにそれから pdf を作ることにします(pandoc から PDF を出力させることもできるようですが、日本語のとおる環境を設定したり次に述べる処理を挟んだりするのがやりにくいので、こういうやり方にします)。

    さて、ここで読み込まれる a.tex, b.tex を md から pandoc で生成するのですが、単純にやるだけでは、HTML 向けに書いていたリンクのところが

    これらは\href{b.html\#shita}{「下ごしらえ」}で使います。
    

    のようになってしまいます。これではよろしくないので、

    sed 's/\(\[[^\]*\]\)[\(][^#]*\(#[^\)]*\)[\)]/\1(\2)/g' a.md \
    | pandoc -t latex \
    | sed 's/\(\\hyperref\[\([^\]*\)\]\)[\{][^\}]*[\}]/\1\{\\ref\{\2\}\}/g' \
    > a.tex
    

    のようにします。バックスラッシュと括弧だらけでわかりにくいですが、前段の sed

    [「下ごしらえ」](b.html#shita)
    

    [「下ごしらえ」](#shita)
    

    のように、丸カッコ内のファイル名相当の部分を削除します。これで生成物の当該部分は

    \hyperref[shita]{「下ごしらえ」}
    

    となるので、後段の sed でこれを

    \hyperref[shita]{\ref{shita}}
    

    のように書き換えます。

    これにより、生成物は

    a.tex
    \section{はじめに}\label{hajimeni}
    
    \ldots{}
    
    \section{用意するもの}\label{ux7528ux610fux3059ux308bux3082ux306e}
    
    \ldots{}
    
    \subsection{道具}\label{dougu}
    
    \begin{itemize}
    \itemsep1pt\parskip0pt\parsep0pt
    \item
      包丁
    \item
      まな板
    \item
      \ldots{}
    \end{itemize}
    
    これらは\hyperref[shita]{\ref{shita}}で使います。
    
    \begin{itemize}
    \itemsep1pt\parskip0pt\parsep0pt
    \item
      大きな鍋\index{おおきななべ@大きな鍋}
    \item
      \ldots{}
    \end{itemize}
    
    これらは\hyperref[chouri]{\ref{chouri}}で使います。
    
    \subsection{材料}\label{zairyo}
    
    \ldots{}
    
    b.tex
    \section{手順}\label{ux624bux9806}
    
    \subsection{下ごしらえ}\label{shita}
    
    ここで使う材料は\hyperref[zairyo]{\ref{zairyo}}にまとめてあります。 \ldots{}
    
    \subsection{調理}\label{chouri}
    
    \ldots{}
    大きな鍋\index{おおきななべ@大きな鍋}(\hyperref[dougu]{\ref{dougu}}を参照のこと)を使います。
    \ldots{}
    
    \subsection{盛り付け}\label{moritsuke}
    
    \section{おわりに}\label{ux304aux308fux308aux306b}
    
    \ldots{}
    

    となります。

    これで相互参照が正しくなった中間ソース a.tex, b.tex ができましたので、main.tex を

    platex main
    platex main
    mendex main
    platex main
    dvipdfmx main
    

    と処理して、最終的に main.pdf を得ることができます。

    EPUB

    pandoc は EPUB 形式を出力することもできます。

    ソースは複数ファイルに分割されていても成果物はひとつにまとまっていたほうがいいので cat でつなぎます。また、HTML 向けに付けていたリンクの書き方を変更して(LaTeX の場合の前処理と同じです)、pandoc にかけます。

    cat a.md b.md \
    | sed 's/\(\[[^\]*\]\)[\(][^#]*\(#[^\)]*\)[\)]/\1(\2)/g' \
    | pandoc --self-contained -o main.epub
    

    これで最終成果物の main.epub ができます。LaTeX の索引のために挿入しておいた \index{} は無視されるので、特に気にすることはありません。

    HTML や LaTeX、EPUB を出力する際には、もっと適切な pandoc のオプションを付けたり、テンプレートを用意したほうがいいのですが、ここでは相互参照に絞って説明するため、これらを割愛しました。