ASP.NET Web API をビルドしただけなのに、bin 配下に「zh-Hans」という見慣れないフォルダーが増えて困ったことはありませんか。これは不正なファイルではなく、.NET の多言語リソース(サテライトアセンブリ)の出力先です。生成理由の見分け方と、不要な場合に抑止する具体策を整理します。
bin 配下に「zh-Hans」フォルダーができる現象とは
Visual Studio で ASP.NET Web API(.NET Framework / .NET 5+ いずれでも起こり得ます)をビルドすると、出力先(多くは bin)にカルチャ名のフォルダーが自動生成されることがあります。代表例が zh-Hans(中国語・簡体字)です。
典型的には、次のような構成になります。
bin/
YourApi.dll
YourApi.pdb
zh-Hans/
SomeLibrary.resources.dll
ポイントは、「zh-Hans フォルダーの中身は多くの場合 *.resources.dll」であることです。ここが原因特定の近道になります。
zh-Hans とは何か(結論:サテライトアセンブリの出力先)
zh-Hans はカルチャ(言語・地域)を表す名前で、「中国語・簡体字」を意味します。.NET では、画面表示用の文字列やエラーメッセージなどのローカライズ(多言語化)を、リソース(.resx)とサテライトアセンブリ(*.resources.dll)の仕組みで扱います。
サテライトアセンブリは、メインの DLL とは別に「特定言語のリソースだけ」を含む DLL で、慣習として次の配置になります。
- メイン DLL:
bin\SomeLibrary.dll - 言語別リソース DLL:
bin\zh-Hans\SomeLibrary.resources.dll
.NET は実行時に CurrentUICulture(UI 表示用カルチャ)に応じて、該当フォルダーの *.resources.dll を自動で読み込みます。つまり zh-Hans は、中国語・簡体字向けの文字列リソースを格納するための「器」です。
| フォルダー名(例) | 意味 | よくある用途 |
|---|---|---|
ja / ja-JP | 日本語(地域指定あり/なし) | UI 文言、検証エラー、例外メッセージ |
en / en-US | 英語 | 英語 UI、ログ、標準メッセージ |
zh-Hans | 中国語(簡体字) | 中国語 UI、例外/検証メッセージの翻訳 |
zh-Hant | 中国語(繁体字) | 台湾/香港向け UI |
なぜ ASP.NET Web API のビルドで zh-Hans が出てくるのか
「中国語なんて使っていないのに…」という状況でも、zh-Hans フォルダーが生成されるのは珍しくありません。理由は大きく分けて 2 つです。
原因1:プロジェクト内に言語別 .resx がある
プロジェクト内に、言語別のリソースファイルがある場合、ビルド時にサテライトアセンブリが生成され、対応するカルチャフォルダーが出力されます。
例:
Resources.resx(既定/ニュートラル)Resources.zh-Hans.resx(中国語・簡体字)
この場合は「プロジェクト自身が zh-Hans を持っている」ので、出力されて当然です。
原因2:参照している DLL / NuGet が多言語リソースを含んでいる
ASP.NET Web API は、実体は「あなたのコード + 参照ライブラリの集合」です。参照している DLL や NuGet パッケージが多言語リソースを含むと、ビルド(または発行)時に、そのサテライトアセンブリが bin\zh-Hans にコピーされます。
とくに Web API では、次のような用途のライブラリが多言語リソースを同梱しがちです。
- 入力検証(Validation)や DataAnnotations 系のエラーメッセージ
- 認証/認可、セキュリティ周りの標準メッセージ
- JSON、HTTP、暗号などの基盤系ライブラリが提供する例外メッセージ
- UI を持たないのに、例外メッセージやログ文言を多言語化しているコンポーネント
| 原因 | 見分け方 | 対処の方向性 |
|---|---|---|
| プロジェクト内 .resx 起因 | bin\zh-Hans に YourApi.resources.dll がある | 不要なら .resx を削除/除外、または出力言語を限定 |
| 参照 DLL / NuGet 起因 | bin\zh-Hans の DLL 名がライブラリ名になっている | 言語出力を限定、または参照の見直し(不要なら外す) |
まず確認:bin\zh-Hans の中身を見れば「犯人」が分かる
原因切り分けで最初にやるべきことはシンプルです。bin\zh-Hans フォルダーの中にあるファイル名を見てください。
チェック手順
- エクスプローラーで
bin\zh-Hansを開く *.resources.dllの「ベース名」を確認する(例:FooBar.resources.dllのFooBar)- そのベース名の DLL がどこから来ているかを特定する(参照 DLL か、NuGet か、プロジェクト自身か)
たとえば次のような中身なら、Contoso.Common が zh-Hans のリソースを持っている、と推測できます。
bin/zh-Hans/
Contoso.Common.resources.dll
Contoso.Validation.resources.dll
PowerShell で一覧を取る(CI/CD や原因調査に便利)
Get-ChildItem -Path ".\bin\zh-Hans" -Filter "*.resources.dll" | Select-Object Name
出てきた DLL 名をキーに、Visual Studio の「参照」や NuGet の依存関係(ソリューション全体のパッケージ一覧)へ当たりを付けると、調査が一気に短縮できます。
そもそも不要?残すべき?判断のポイント
結論から言うと、多くの Web API では zh-Hans が存在しても動作上の問題は起こりません。ただし「不要な成果物はできるだけ減らしたい」という要求があるのも事実です。次の観点で判断すると納得感が出ます。
| 観点 | 残してよいケース | 削りたいケース |
|---|---|---|
| サイズ | 数百 KB〜数 MB 程度で許容できる | コンテナ/サーバレス等で成果物を極力小さくしたい |
| 運用 | 特に気にしない、標準的な発行フロー | 配布物の差分管理、セキュリティ監査で「不要物」として扱われる |
| 表示言語 | 将来的に多言語対応する可能性がある | ログやエラーメッセージは日本語/英語に固定したい |
| 実行時カルチャ | サーバ OS/環境が多言語で動く | サーバ環境は単一言語で運用し、UI Culture を固定する |
「絶対に消すべきもの」ではない一方で、成果物を明確にコントロールしたいなら、生成を抑止(または発行物から除外)する価値はあります。
対処法:出力言語を限定して zh-Hans を生成させない
不要なカルチャフォルダーを抑止する最も実務的な方法は、ビルド/発行成果物に含めるサテライトアセンブリの言語を限定することです。MSBuild のプロパティ SatelliteResourceLanguages を使います。
.csproj に設定する(推奨:ビルドと発行の両方に効かせやすい)
例:英語だけに絞る
<PropertyGroup>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
環境や参照によっては en ではなく、フォルダー名と一致する en-US のような指定が必要になることがあります。例えば出力側が en-US であるなら、次のように合わせます。
<PropertyGroup>
<SatelliteResourceLanguages>en-US</SatelliteResourceLanguages>
</PropertyGroup>
日本語だけにしたい場合は、ja または ja-JP を同様に指定します(出力されるカルチャ名に合わせるのがコツです)。
複数言語を許可する場合(例:日本語と英語)
<PropertyGroup>
<SatelliteResourceLanguages>ja-JP;en-US</SatelliteResourceLanguages>
</PropertyGroup>
| 目的 | 設定例 | 期待される挙動 |
|---|---|---|
| 英語のみ | en または en-US | それ以外(zh-Hans など)のカルチャフォルダーを出力しにくくする |
| 日本語のみ | ja または ja-JP | 日本語以外のリソース DLL を省く |
| 日本語+英語 | ja-JP;en-US | 2 言語だけを残す |
CLI で発行時だけ指定する(CI/CD で便利)
プロジェクトファイルを触りたくない場合や、環境別に切り替えたい場合は、発行コマンドでプロパティを渡すのが実務的です。
dotnet publish -c Release /p:SatelliteResourceLanguages=ja-JP
「開発環境はそのまま」「本番の発行物だけ絞る」といった運用がしやすくなります。
対処法:プロジェクト内の .resx(言語別リソース)を整理する
もし bin\zh-Hans の中に YourApi.resources.dll(またはプロジェクト名に近い resources.dll)があるなら、プロジェクト自身が zh-Hans リソースを持っている可能性が高いです。
よくある .resx の命名パターン
| ファイル名 | 意味 | 不要なら |
|---|---|---|
Resources.resx | 既定(ニュートラル)リソース | 基本は残す(削ると参照コードが壊れることが多い) |
Resources.ja.resx | 日本語リソース | 日本語固定なら残す/英語固定なら削除検討 |
Resources.zh-Hans.resx | 中国語(簡体字)リソース | 不要なら削除または「除外」 |
対処としては、使っていない言語別 .resx を削除するか、プロジェクトから除外します。削除する前に、検索で当該リソースキーが参照されていないか(Resources.xxx など)を確認すると安全です。
対処法:参照 DLL / NuGet が原因の場合の考え方
bin\zh-Hans に入っている *.resources.dll のベース名が、あなたのプロジェクトではなく外部ライブラリ名である場合、原因は参照側です。この場合、根本対策の選択肢は次の 2 つになります。
選択肢A:言語の出力を限定する(実務では最優先)
外部ライブラリは更新や差し替えの影響が大きいので、まずは SatelliteResourceLanguages による出力制御が安定です。ライブラリが何を参照していても、発行物として「必要な言語だけ」を残せます。
選択肢B:参照を外す・置き換える(本当に不要な場合のみ)
外部ライブラリが不要なら参照を外すのが最もクリーンです。ただし「zh-Hans が出るから」という理由だけで参照を外すのは危険です。実際には、そのライブラリは多言語化以外の機能が本体であり、リソースはおまけに過ぎないことがほとんどだからです。
判断の基準として、次の質問に答えると良いです。
- そのライブラリを外した場合、API の機能要件は満たせるか?
- 代替ライブラリはあるか?学習コストや移行コストは許容できるか?
- サイズ削減の効果は、コストに見合うか?(resources.dll は通常そこまで巨大ではない)
最終手段:ビルド後に zh-Hans フォルダーを削除する
「どうしても成果物から消したい」「一部の環境だけ消したい」という場合、ビルド後や発行後にフォルダーを削除する方法もあります。原因が残っている限り次回ビルドで再生成されますが、成果物としての出力を揃える目的には有効です。
MSBuild ターゲットで Build 後に削除する例
<Target Name="RemoveZhHansAfterBuild" AfterTargets="Build">
<RemoveDir Directories="$(OutDir)zh-Hans" Condition="Exists('$(OutDir)zh-Hans')" />
</Target>
Publish 後(発行物)から削除する例
<Target Name="RemoveZhHansAfterPublish" AfterTargets="Publish">
<RemoveDir Directories="$(PublishDir)zh-Hans" Condition="Exists('$(PublishDir)zh-Hans')" />
</Target>
| 方法 | メリット | デメリット/注意点 |
|---|---|---|
SatelliteResourceLanguages で制御 | 原因に依存せず安定、意図が明確 | カルチャ名の指定を誤ると期待通りにならないことがある |
| .resx を削除/除外 | 根本原因を解消できる | 参照箇所があるとビルドエラー/欠落につながる |
| AfterBuild/AfterPublish で削除 | 即効性が高い、環境別に制御しやすい | 「生成されない」わけではない。将来の多言語対応を潰す可能性 |
よくある疑問
フォルダーを手動で消しても大丈夫?
基本的に、Web API の動作そのものは壊れにくいです(該当カルチャのリソースが見つからないだけなので、ニュートラル言語へフォールバックすることが多い)。ただし、サーバの CurrentUICulture が zh-Hans になる環境で「中国語の文言が出るべき」設計なら、期待する表示が変わる可能性があります。
なぜ zh-Hans だけ出るの?
参照ライブラリが「対応している言語」を同梱している結果です。あるライブラリが zh-Hans を持っていても、ja-JP を持っていない(またはその逆)ことは普通にあります。つまり、あなたのプロジェクトが中国語対応しているというより、依存関係が国際化対応しているというだけのケースが多いです。
ASP.NET Web API のレスポンス言語と関係ある?
直接的には関係しないことが多いです。Web API の JSON レスポンスは、通常はあなたのコードが生成する文字列に依存します。一方、サテライトアセンブリが影響するのは、例外メッセージ、フレームワークの標準メッセージ、検証エラーメッセージなど「ライブラリ側が用意した文字列」です。
まとめ:zh-Hans は「異常」ではなく「多言語リソースの成果物」
bin\zh-Hansは、.NET のローカライズ用リソース(サテライトアセンブリ)を格納するフォルダー- 原因は「プロジェクト内 .resx」または「参照 DLL / NuGet が多言語リソースを含む」のどちらかが多い
- まず
bin\zh-Hans内の*.resources.dll名を見れば、原因特定が早い - 不要なら
SatelliteResourceLanguagesで出力言語を絞るのが安定策 - どうしても消したい場合は Build/Publish 後に削除するターゲット追加も可能
「勝手に増えるフォルダー」は不安になりがちですが、仕組みが分かればコントロールできます。まずは中身の DLL 名を確認し、必要な言語だけを残す形で成果物を整えるのがおすすめです。

コメント