Mxhlix

「プレビューしてからPNGとしてダウンロード」するWebツールを大量に運用しています——名札、証明書生成ツール、プライスカード、バッジ——5言語に対応:日本語、英語、スペイン語、フランス語、ポルトガル語。

Canvas 2Dのテキスト描画は、日本語と英語だけをテストしている限りは正しく見えます。

es/fr/ptを通すと壊れます。

何度もつまずいた結果、これらの失敗は4つのパターンに集約されます。

前提:ラテン言語は日本語より1.4〜2倍長くなる

まずデザインデータを。同じラベルを5つのロケールで計測した結果:

ja en es fr pt
ツール名 22文字 35 62 48 50
「Standard」ボタン 4 8 10 20 12

目安:fr/ptはjaより1.4〜1.7倍長くなり、esは最大で約3倍に膨らむこともあります。日本語向けに調整したフォントサイズとmaxWidthは、ラテン言語向けには合いません。4つの失敗パターンはすべてこの前提から生じています。

パターン1: text.split(/\s+/) による自前ラッピングがCJKで崩壊する

定番のスニペット——スペースで分割し、単語ごとに折り返す——は、日本語や中国語では何もせず、単語がスペース区切りでないため、文章全体が1つの折り返せないトークンとなり、キャンバスの端でクリップされます。

実際の日本語入力でテストし、最終行が最後の文字まで描画されていることを確認してください。「だいたい表示された」は合格ではありません。

パターン2: ASCII限定のトークナイザがアクセント付き文字で単語を分割する

パターン1を [A-Za-z0-9'\-_] のような文字クラスによるトークナイザで修正すると、今度は別の問題が発生します:ç é ã ó ñ はそのクラスに含まれないため、produçãoprodu / ç / ão と単語の途中で分割されます。

英語のテストではこの問題を検出できません。

fr/es/ptのサンプルで実際のPNGを生成し、アクセント付き文字周辺を目視してください。他の検出方法は見つかりませんでした——文字列比較テストでは描画レベルの分割は見えません。

パターン3: 末尾の重要な単語が「…」に消える

fr/ptはレイアウト調整の基準となったjaより1.4〜1.7倍長いため、テキストが2行目で溢れて省略記号が付きます。残酷な点は、消えるのがフレーズの末尾——しばしば意味的に重要な単語(production / produção など)であることです。

解決策は、フィールドを2つのクラスに分けることでした。省略を許すフィールド(説明文)は折り返し+省略記号付きに。絶対に省略してはいけないフィールド(タイトル、名前)は自動フィット:オフスクリーンキャンバスで measureText を使ってフィットするフォントサイズを探し、そのサイズで描画します。タイトルに省略記号が付くのは破損した成果物なので、2つの戦略を混ぜてはいけません。

パターン4: プレビューとダウンロードしたPNGで改行位置が異なる

最も厄介なケース。パターン3の自動フィットをキャンバス側でのみ実装し、DOMプレビューは固定フォントサイズのままにすると、画面上で見える改行とPNG内の改行が一致しなくなります。ユーザーから見ると、ツールの核心の約束——「見たままをダウンロード」——が破綻します。

解決策:自動フィットのフォントサイズ決定を1箇所(オフスクリーンキャンバスの計測)に集約し、その結果のサイズをキャンバス描画とプレビューDOMの両方に適用する(style.fontSize)。合格条件:プレビューとダウンロードしたPNGの行数と改行位置が、5つのロケールすべてで一致すること。

リリース前チェックリスト

新しい画像出力ツールごとに:

  • [ ] ja: CJKが最終行の最後の文字まで描画され、端でクリップされていない
  • [ ] fr / es / pt: 実際のPNGを生成し、ç é ã ó ñ の周辺で単語が分割されていない
  • [ ] fr / pt: 省略記号が重要な末尾の単語を飲み込んでいない
  • [ ] 5つのロケールすべて: プレビュー(DOM)とダウンロードしたPNGの改行位置と行数が一致する

enとjaだけを確認して「多言語対応:完了」と宣言することが、最大の落とし穴でした。

制限と注意事項

文字数の比率は自社ツール群(ユーティリティツールの名前、説明、UIラベル)から計測したものです。コンテンツの種類が異なれば比率も変わります。

自動化の限界について:パターン2と4は静的解析では全く検出できません。PNGを生成して目視するしかありませんでした。5ロケール×生成チェックは実際のコストであり、何を省略しても本番環境で表面化します。


検証日:2026年4月〜5月。環境:Canvas 2D API / vanilla JS / 本番環境のja・en・es・fr・ptロケール。