Windows Terminalの日本語が読みにくい原因はフォント未設定だった。UDEV Gothicを管理者権限なしで入れる

開発misc-dev

Windows Terminalの日本語が読みにくい原因はフォント未設定だった。UDEV Gothicを管理者権限なしで入れる

ターミナルで作業していて、日本語がずっと読みにくかった。そもそも自分がどのターミナルを使っているかも把握していなかったので、Claude Codeに調査から設定までを任せた。

先に結論を書く。使っていたのはWindows Terminalで、読みにくさの原因はフォントを一度も設定していなかったことだった。既定フォントのCascadia Monoは日本語のグリフ(字形データ)を持たないため、日本語部分だけ別フォントで代替描画され、英数字とチグハグな見た目になる。日本語対応の等幅フォント「UDEV Gothic」を入れてフォント名を1行指定するだけで解決した。管理者権限は不要で、ターミナルの乗り換えも不要だった。

使っているターミナルの確認方法

Windows Terminalで動いているかどうかは、環境変数 WT_SESSION で判定できる。値が入っていればWindows Terminal上で動いている。

# PowerShellの場合
$env:WT_SESSION

# Git Bashの場合
echo $WT_SESSION

設定ファイルの場所も確認しておく。ストア版のWindows Terminalなら次のパスにある。

%LOCALAPPDATA%\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json

原因: フォント未指定だと日本語はフォールバック描画になる

settings.jsonを開くと、フォント設定はサイズ指定だけで、フォント名(face)がどこにもなかった。

"profiles":
{
    "defaults":
    {
        "font":
        {
            "size": 10
        }
    }
}

この状態だと既定のCascadia Monoで描画される。Cascadia Monoは英数字専用のフォントで、日本語のグリフを持たない。持たない文字は、DirectWriteが別のフォントに1文字単位で肩代わりさせる(フォールバック)。結果として、英数字と日本語で太さ・幅・デザインがバラバラになる。読みにくさの正体はこれだった。

つまりターミナル自体に問題があるわけではない。日本語グリフを持つ等幅フォントを指定すれば直る。

フォントはUDEV Gothicを選んだ

日本語対応のプログラミング用等幅フォントは定番が3つある。

  • UDEV Gothic — モリサワBIZ UDゴシック + JetBrains Mono。ユニバーサルデザイン書体がベースで、日本語の判読性を重視するならこれ
  • HackGen(白源) — Hack + 源柔ゴシック。丸みのある定番フォント
  • PlemolJP — IBM Plex Mono + IBM Plex Sans JP。細身でモダン

今回はUDEV Gothicにした。バリエーションのうち「NF」付き(Nerd Fonts入り)を選ぶと、プロンプトやCLIツールが使うアイコン文字も化けずに表示される。ターミナル用途ならNF一択でいい。

wingetにはパッケージがなかったので(winget search udev で見つからない)、GitHubリリースからzipを取得する。この記事を書いた時点の最新版はv2.2.0だった。

管理者権限なしでインストールする

TTFファイルを右クリックして「インストール」を選べば、管理者権限なしのユーザー単位インストールになる。数個ならこれで足りる。

今回はNF標準の4書体と35NFの4書体、計8ファイルをまとめて入れたかったので、PowerShellスクリプトで同じことをやった。ユーザー単位インストールの実体は「%LOCALAPPDATA%\Microsoft\Windows\Fonts へのコピー」と「HKCUレジストリへの登録」の2つだけで、どちらも管理者権限が要らない。

# 展開したzipのフォルダを指定
$src = "C:\path\to\UDEVGothic_NF_v2.2.0"
$dst = "$env:LOCALAPPDATA\Microsoft\Windows\Fonts"
New-Item -ItemType Directory -Force -Path $dst | Out-Null

$reg = "HKCU:\Software\Microsoft\Windows NT\CurrentVersion\Fonts"
if (-not (Test-Path $reg)) { New-Item -Path $reg -Force | Out-Null }

$names = @{
  "UDEVGothicNF-Regular.ttf"      = "UDEV Gothic NF (TrueType)"
  "UDEVGothicNF-Bold.ttf"         = "UDEV Gothic NF Bold (TrueType)"
  "UDEVGothicNF-Italic.ttf"       = "UDEV Gothic NF Italic (TrueType)"
  "UDEVGothicNF-BoldItalic.ttf"   = "UDEV Gothic NF Bold Italic (TrueType)"
  "UDEVGothic35NF-Regular.ttf"    = "UDEV Gothic 35NF (TrueType)"
  "UDEVGothic35NF-Bold.ttf"       = "UDEV Gothic 35NF Bold (TrueType)"
  "UDEVGothic35NF-Italic.ttf"     = "UDEV Gothic 35NF Italic (TrueType)"
  "UDEVGothic35NF-BoldItalic.ttf" = "UDEV Gothic 35NF Bold Italic (TrueType)"
}
foreach ($f in $names.Keys) {
  Copy-Item -Force (Join-Path $src $f) (Join-Path $dst $f)
  New-ItemProperty -Path $reg -Name $names[$f] `
    -Value (Join-Path $dst $f) -PropertyType String -Force | Out-Null
}

HKCUに登録したフォントは次回ログオン時にWindowsが自動で読み込む。恒久設定としてはこれで完了している。

起動中のアプリに即反映させる

レジストリ登録だけだと、いま起動中のアプリはフォントを認識しない。ログオンし直さずに反映させるには、AddFontResource で現在のセッションに読み込み、WM_FONTCHANGE を全ウィンドウに通知する。

Add-Type -Name FontLoader -Namespace Win32 -MemberDefinition @"
[DllImport("gdi32.dll", CharSet = CharSet.Auto)]
public static extern int AddFontResource(string lpFileName);
[DllImport("user32.dll")]
public static extern int SendNotifyMessage(IntPtr hWnd, uint Msg, UIntPtr wParam, IntPtr lParam);
"@
$dst = "$env:LOCALAPPDATA\Microsoft\Windows\Fonts"
Get-ChildItem $dst -Filter "UDEVGothic*NF*.ttf" | ForEach-Object {
  [void][Win32.FontLoader]::AddFontResource($_.FullName)
}
# WM_FONTCHANGE (0x001D) を全ウィンドウにブロードキャスト
[void][Win32.FontLoader]::SendNotifyMessage([IntPtr]0xffff, 0x001D, [UIntPtr]::Zero, [IntPtr]::Zero)

インストールできたかどうかは、フォントファミリーの列挙で確認できる。次のコマンドで UDEV Gothic NFUDEV Gothic 35NF が出てくれば成功している。

Add-Type -AssemblyName System.Drawing
(New-Object System.Drawing.Text.InstalledFontCollection).Families |
  Where-Object { $_.Name -like "*UDEV*" } | ForEach-Object { $_.Name }

ここで出てくる名前が、次のステップでWindows Terminalに指定する正式なフォントファミリー名になる。ファイル名ではなくこの名前を使う。

Windows Terminalに設定する

settings.jsonの profiles.defaults.fontface を1行足す。defaults に書けば全プロファイル(PowerShell、Git Bash、WSL等)へ一括で効く。

"profiles":
{
    "defaults":
    {
        "font":
        {
            "face": "UDEV Gothic 35NF",
            "size": 10
        }
    }
}

GUIから設定する場合は「設定 → 既定値 → 外観 → フォントフェイス」で同じ場所が書き換わる。Windows Terminalはsettings.jsonの変更を自動で再読み込みするので、保存した瞬間に、開いているウィンドウの表示が切り替わる。切り替わらないときだけ、フォント列挙のキャッシュが古い可能性があるのでWindows Terminalを再起動する。

コードを読むなら35NF(半角:全角 = 3:5)

UDEV Gothicには半角と全角の幅の比が違う2系統がある。

  • UDEV Gothic NF — 半角:全角 = 1:2。日本語の文章が中心ならこちら。全角2文字と半角4文字の幅が一致するので、桁揃えのテキストアートや表も崩れない
  • UDEV Gothic 35NF — 半角:全角 = 3:5。半角が一回り広く、英数字が読みやすい。コードを読む時間が長いならこちら

最初は1:2のNFを設定して日本語の読みやすさを確認し、コードを読む機会が多いことを踏まえて35NFに切り替えた。両方インストールしておけば face の1行を書き換えるだけで行き来できるので、実際の画面で見比べて決めればいい。

まとめ

  • ターミナルの日本語が読みにくいとき、疑うのはターミナル本体より先にフォント設定。face 未指定ならフォールバック描画が起きている
  • UDEV Gothic NFはGitHubリリースから取得する。ユーザー単位インストール(%LOCALAPPDATA% へのコピー + HKCUレジストリ登録)なら管理者権限は不要
  • 起動中のアプリへの即時反映は AddFontResource + WM_FONTCHANGE で足りる。ログオンし直しは要らない
  • 設定は settings.json の profiles.defaults.font.face に1行。コード中心なら35NF、日本語文章中心ならNFを選ぶ