Skill v1.0.1
currentAutomated scan100/1003 files
version: "1.0.1" name: dotnet-cpp-localizer description: Comprehensive internationalization (i18n) and localization (l10n) for .NET and C++ applications. Generate resource files, manage translations, and implement best practices for multi-language support.
.NET & C++ Localizer Skill
.NETとC++アプリケーションの国際化(i18n)と地域化(l10n)を完全サポートするスキルです。
概要
このスキルは、.NET(.resx)とC++(gettext/ICU)の両方に対応した、エンタープライズレベルの国際化ソリューションを提供します。リソースファイル生成、翻訳管理、ベストプラクティス適用まで、国際化のすべてをカバーします。
主な機能
- 🎯 .NET サポート: .resx、IStringLocalizer、ASP.NET Core localization
- 🎯 C++ サポート: gettext (.po/.pot)、ICU、Boost.Locale
- 📦 リソース生成: 自動リソースファイル作成
- 🔍 文字列抽出: ハードコードされた文字列の自動検出
- 🌐 翻訳管理: 複数言語の翻訳ファイル管理
- ✅ 品質チェック: 翻訳漏れ、重複、フォーマットエラー検出
- 📊 進捗トラッキング: 言語別の翻訳完了率
- 🔄 同期ツール: コード変更への自動追従
- 🎨 複数形対応: .NET plural rules、gettext ngettext
- 📱 文化対応: 日付・通貨・数値のロケール別フォーマット
サポート技術
.NET ファミリー
- .NET Core / .NET 6/7/8/9
- ASP.NET Core (MVC, Razor Pages, Blazor)
- WPF (Windows Presentation Foundation)
- WinForms (Windows Forms)
- Xamarin (iOS/Android)
- .NET MAUI (Multi-platform App UI)
- Unity (C# ゲームエンジン)
C++ フレームワーク
- gettext - GNU翻訳システム(最も人気)
- ICU - International Components for Unicode
- Boost.Locale - C++標準ライブラリ風API
- Qt Linguist - Qt フレームワーク (.ts ファイル)
- wxWidgets - クロスプラットフォームGUI
使用方法
.NET アプリケーションの国際化
基本的なリソースファイル生成
.NET Coreプロジェクトに国際化を追加:プロジェクトタイプ: ASP.NET Core MVC言語: 英語(デフォルト)、日本語、中国語、スペイン語リソース場所: Resources/文化: ja-JP, zh-CN, es-ESタスク:1. .resx ファイル生成2. IStringLocalizer 設定3. Startup.cs 設定4. ハードコード文字列の抽出と置き換え
WPF アプリケーション
WPF デスクトップアプリに多言語対応:言語: 英語、日本語、ドイツ語リソース: Properties/Resources.resxUI更新: すべてのラベル、ボタン、メッセージボックス言語切り替え: ランタイムで切り替え可能
C++ アプリケーションの国際化
gettext 統合
C++ コンソールアプリケーションにgettextを統合:ライブラリ: GNU gettext言語: 英語、日本語、フランス語ドメイン: myapp出力: po/ja/myapp.po, po/fr/myapp.poタスク:1. gettext セットアップコード生成2. 文字列抽出(xgettext)3. .pot/.po ファイル生成4. コード修正(_() マクロ)
ICU 統合
C++ プロジェクトにICUを統合:機能:- Unicode文字列処理- 日付・時刻フォーマット(ロケール別)- 数値・通貨フォーマット- 複数形ルール- ソート・検索(ロケール対応)
.NET 実装パターン
1. ASP.NET Core MVC の国際化
生成されるファイル構成:
MyWebApp/├── Resources/│ ├── Controllers/│ │ ├── HomeController.en.resx│ │ ├── HomeController.ja.resx│ │ └── HomeController.zh.resx│ ├── Views/│ │ ├── Home/│ │ │ ├── Index.en.resx│ │ │ ├── Index.ja.resx│ │ │ └── Index.zh.resx│ │ └── Shared/│ │ ├── _Layout.en.resx│ │ └── _Layout.ja.resx│ └── SharedResources.resx├── Program.cs (または Startup.cs)└── appsettings.json
Program.cs (.NET 6+):
using Microsoft.AspNetCore.Localization;using Microsoft.Extensions.Options;using System.Globalization;var builder = WebApplication.CreateBuilder(args);// Localization サービス追加builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");builder.Services.AddControllersWithViews().AddViewLocalization().AddDataAnnotationsLocalization();// サポートする文化を設定var supportedCultures = new[]{new CultureInfo("en"),new CultureInfo("ja"),new CultureInfo("zh"),new CultureInfo("es")};builder.Services.Configure<RequestLocalizationOptions>(options =>{options.DefaultRequestCulture = new RequestCulture("en");options.SupportedCultures = supportedCultures;options.SupportedUICultures = supportedCultures;// クッキーベースの文化選択options.RequestCultureProviders.Insert(0, new CookieRequestCultureProvider());});var app = builder.Build();// Localization ミドルウェア追加(重要: UseRouting より前)app.UseRequestLocalization(app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);app.UseRouting();app.UseAuthorization();app.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");app.Run();
Resources/Controllers/HomeController.ja.resx:
<?xml version="1.0" encoding="utf-8"?><root><data name="Welcome" xml:space="preserve"><value>ようこそ</value></data><data name="HelloMessage" xml:space="preserve"><value>こんにちは、{0}さん!</value></data><data name="ItemCount" xml:space="preserve"><value>{0} 件のアイテム</value></data></root>
HomeController.cs:
using Microsoft.AspNetCore.Mvc;using Microsoft.Extensions.Localization;public class HomeController : Controller{private readonly IStringLocalizer<HomeController> _localizer;public HomeController(IStringLocalizer<HomeController> localizer){_localizer = localizer;}public IActionResult Index(){// リソースから文字列取得ViewData["Message"] = _localizer["Welcome"];// パラメータ付きvar userName = "田中";ViewData["Greeting"] = _localizer["HelloMessage", userName];// 複数形対応var count = 5;ViewData["Items"] = _localizer["ItemCount", count];return View();}[HttpPost]public IActionResult SetLanguage(string culture, string returnUrl){Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName,CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) });return LocalRedirect(returnUrl);}}
Views/Home/Index.cshtml:
@using Microsoft.AspNetCore.Mvc.Localization@inject IViewLocalizer Localizer<h1>@Localizer["Welcome"]</h1><p>@ViewData["Greeting"]</p><p>@ViewData["Items"]</p><!-- 言語切り替え --><form asp-action="SetLanguage" asp-controller="Home" method="post"><input type="hidden" name="returnUrl" value="@Context.Request.Path" /><select name="culture" onchange="this.form.submit()"><option value="en">English</option><option value="ja">日本語</option><option value="zh">中文</option><option value="es">Español</option></select></form>
2. WPF デスクトップアプリケーション
App.xaml.cs:
using System.Globalization;using System.Threading;using System.Windows;public partial class App : Application{protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);// ユーザー設定から言語読み込みvar cultureName = Properties.Settings.Default.Language ?? "en";SetLanguage(cultureName);}public static void SetLanguage(string cultureName){var culture = new CultureInfo(cultureName);Thread.CurrentThread.CurrentCulture = culture;Thread.CurrentThread.CurrentUICulture = culture;// WPFのリソースディクショナリを更新CultureInfo.DefaultThreadCurrentCulture = culture;CultureInfo.DefaultThreadCurrentUICulture = culture;}}
MainWindow.xaml.cs:
using System.Windows;public partial class MainWindow : Window{public MainWindow(){InitializeComponent();UpdateUI();}private void UpdateUI(){// リソースから文字列取得Title = Properties.Resources.AppTitle;WelcomeLabel.Content = Properties.Resources.Welcome;LoginButton.Content = Properties.Resources.Login;}private void LanguageComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e){if (LanguageComboBox.SelectedItem is ComboBoxItem item){var culture = item.Tag.ToString();App.SetLanguage(culture);// 設定を保存Properties.Settings.Default.Language = culture;Properties.Settings.Default.Save();// UIを更新(または再起動)UpdateUI();}}}
Properties/Resources.resx (英語):
<data name="AppTitle" xml:space="preserve"><value>My Application</value></data><data name="Welcome" xml:space="preserve"><value>Welcome!</value></data><data name="Login" xml:space="preserve"><value>Login</value></data>
Properties/Resources.ja.resx (日本語):
<data name="AppTitle" xml:space="preserve"><value>私のアプリケーション</value></data><data name="Welcome" xml:space="preserve"><value>ようこそ!</value></data><data name="Login" xml:space="preserve"><value>ログイン</value></data>
3. .NET MAUI (マルチプラットフォーム)
MauiProgram.cs:
using Microsoft.Extensions.Localization;using System.Globalization;public static class MauiProgram{public static MauiApp CreateMauiApp(){var builder = MauiApp.CreateBuilder();builder.UseMauiApp<App>().ConfigureFonts(fonts =>{fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");});// Localization追加builder.Services.AddLocalization();return builder.Build();}}
Resources/Strings/AppResources.ja.resx:
<data name="Welcome" xml:space="preserve"><value>ようこそ</value></data>
MainPage.xaml.cs:
using Microsoft.Extensions.Localization;public partial class MainPage : ContentPage{private readonly IStringLocalizer<AppResources> _localizer;public MainPage(IStringLocalizer<AppResources> localizer){InitializeComponent();_localizer = localizer;WelcomeLabel.Text = _localizer["Welcome"];}}
C++ 実装パターン
1. gettext による国際化
ファイル構成:
myapp/├── src/│ ├── main.cpp│ └── i18n.h├── po/│ ├── myapp.pot # テンプレート│ ├── ja/│ │ └── myapp.po # 日本語翻訳│ ├── fr/│ │ └── myapp.po # フランス語翻訳│ └── de/│ └── myapp.po # ドイツ語翻訳├── locale/ # コンパイル済み .mo ファイル│ ├── ja/│ │ └── LC_MESSAGES/│ │ └── myapp.mo│ └── fr/│ └── LC_MESSAGES/│ └── myapp.mo└── CMakeLists.txt
i18n.h (ヘッダー):
#ifndef I18N_H#define I18N_H#include <libintl.h>#include <locale.h>// 翻訳マクロ#define _(STRING) gettext(STRING)#define N_(STRING) STRING// 複数形対応#define _n(SINGULAR, PLURAL, N) ngettext(SINGULAR, PLURAL, N)// 初期化関数inline void initI18n(const char* domain, const char* locale_dir) {// ロケール設定setlocale(LC_ALL, "");// gettext設定bindtextdomain(domain, locale_dir);bind_textdomain_codeset(domain, "UTF-8");textdomain(domain);}#endif // I18N_H
main.cpp:
#include <iostream>#include <string>#include "i18n.h"int main(int argc, char* argv[]) {// 国際化初期化initI18n("myapp", "./locale");// 翻訳された文字列を使用std::cout << _("Welcome to My Application!") << std::endl;std::cout << _("Please enter your name: ");std::string name;std::getline(std::cin, name);// パラメータ付き(printfスタイル)printf(_("Hello, %s!\n"), name.c_str());// 複数形対応int count = 5;printf(_n("You have %d new message","You have %d new messages",count),count);std::cout << std::endl;// メニュー表示std::cout << "\n" << _("Menu:") << std::endl;std::cout << "1. " << _("View Profile") << std::endl;std::cout << "2. " << _("Settings") << std::endl;std::cout << "3. " << _("Exit") << std::endl;return 0;}
翻訳ファイル生成手順:
# 1. 翻訳可能な文字列を抽出 (.pot ファイル生成)xgettext --keyword=_ --keyword=_n:1,2 --language=C++ \--add-comments --sort-output \--output=po/myapp.pot \src/*.cpp# 2. 各言語の .po ファイル作成(初回のみ)msginit --input=po/myapp.pot --locale=ja_JP --output=po/ja/myapp.pomsginit --input=po/myapp.pot --locale=fr_FR --output=po/fr/myapp.po# 3. .po ファイルを編集(翻訳者が実施)# 例: po/ja/myapp.po# 4. 既存の .po ファイルを更新(コード変更時)msgmerge --update po/ja/myapp.po po/myapp.pot# 5. .mo ファイルにコンパイルmsgfmt --output-file=locale/ja/LC_MESSAGES/myapp.mo po/ja/myapp.pomsgfmt --output-file=locale/fr/LC_MESSAGES/myapp.mo po/fr/myapp.po
po/ja/myapp.po (日本語翻訳例):
# Japanese translation for myappmsgid ""msgstr """Project-Id-Version: myapp 1.0\n""Content-Type: text/plain; charset=UTF-8\n""Language: ja\n"msgid "Welcome to My Application!"msgstr "私のアプリケーションへようこそ!"msgid "Please enter your name: "msgstr "お名前を入力してください: "msgid "Hello, %s!\n"msgstr "こんにちは、%sさん!\n"# 複数形msgid "You have %d new message"msgid_plural "You have %d new messages"msgstr[0] "%d 件の新しいメッセージがあります"msgid "Menu:"msgstr "メニュー:"msgid "View Profile"msgstr "プロフィールを表示"msgid "Settings"msgstr "設定"msgid "Exit"msgstr "終了"
CMakeLists.txt (ビルド統合):
cmake_minimum_required(VERSION 3.10)project(myapp)set(CMAKE_CXX_STANDARD 17)# gettext ライブラリを探すfind_package(Gettext REQUIRED)find_package(Intl REQUIRED)# 実行ファイルadd_executable(myapp src/main.cpp)# インクルードディレクトリtarget_include_directories(myapp PRIVATE ${Intl_INCLUDE_DIRS})# ライブラリリンクtarget_link_libraries(myapp PRIVATE ${Intl_LIBRARIES})# .po ファイルから .mo ファイルを生成set(LANGUAGES ja fr de)set(PO_DIR ${CMAKE_SOURCE_DIR}/po)set(LOCALE_DIR ${CMAKE_BINARY_DIR}/locale)foreach(LANG ${LANGUAGES})set(PO_FILE ${PO_DIR}/${LANG}/myapp.po)set(MO_DIR ${LOCALE_DIR}/${LANG}/LC_MESSAGES)set(MO_FILE ${MO_DIR}/myapp.mo)# ディレクトリ作成file(MAKE_DIRECTORY ${MO_DIR})# カスタムコマンド: .po → .moadd_custom_command(OUTPUT ${MO_FILE}COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${MO_FILE} ${PO_FILE}DEPENDS ${PO_FILE}COMMENT "Compiling ${LANG} translation")list(APPEND MO_FILES ${MO_FILE})endforeach()# すべての .mo ファイルをビルドadd_custom_target(translations ALL DEPENDS ${MO_FILES})add_dependencies(myapp translations)# インストールinstall(DIRECTORY ${LOCALE_DIR}/ DESTINATION share/locale)
2. ICU による高度な国際化
ICU 使用例:
#include <iostream>#include <unicode/ucnv.h>#include <unicode/unistr.h>#include <unicode/datefmt.h>#include <unicode/numfmt.h>#include <unicode/plurrule.h>#include <unicode/msgfmt.h>using namespace icu;int main() {UErrorCode status = U_ZERO_ERROR;// 1. Unicode文字列処理UnicodeString text("Hello, 世界! 你好!");std::cout << "Length: " << text.length() << " characters" << std::endl;// 2. 日付フォーマット(ロケール別)Locale localeJa("ja_JP");Locale localeEn("en_US");DateFormat* dateFormatJa = DateFormat::createDateInstance(DateFormat::kFull, localeJa);DateFormat* dateFormatEn = DateFormat::createDateInstance(DateFormat::kFull, localeEn);UDate now = Calendar::getNow();UnicodeString dateJa, dateEn;dateFormatJa->format(now, dateJa);dateFormatEn->format(now, dateEn);std::string dateJaUtf8, dateEnUtf8;dateJa.toUTF8String(dateJaUtf8);dateEn.toUTF8String(dateEnUtf8);std::cout << "Date (ja): " << dateJaUtf8 << std::endl;std::cout << "Date (en): " << dateEnUtf8 << std::endl;// 3. 数値フォーマット(通貨)NumberFormat* currencyJa = NumberFormat::createCurrencyInstance(localeJa, status);NumberFormat* currencyEn = NumberFormat::createCurrencyInstance(localeEn, status);double amount = 1234567.89;UnicodeString currencyJaStr, currencyEnStr;currencyJa->format(amount, currencyJaStr);currencyEn->format(amount, currencyEnStr);std::string currencyJaUtf8, currencyEnUtf8;currencyJaStr.toUTF8String(currencyJaUtf8);currencyEnStr.toUTF8String(currencyEnUtf8);std::cout << "Currency (ja): " << currencyJaUtf8 << std::endl;std::cout << "Currency (en): " << currencyEnUtf8 << std::endl;// 4. 複数形ルールPluralRules* pluralRulesEn = PluralRules::forLocale(localeEn, status);for (int i = 0; i <= 5; i++) {UnicodeString keyword = pluralRulesEn->select(i);std::string keywordUtf8;keyword.toUTF8String(keywordUtf8);std::cout << i << " -> " << keywordUtf8 << std::endl;}// 5. MessageFormat (パラメータ付きメッセージ)UnicodeString pattern("{0} has {1, plural, ""one {# apple} ""other {# apples}}.");MessageFormat msgFormat(pattern, localeEn, status);UnicodeString name("Alice");int appleCount = 3;Formattable args[] = { name, appleCount };UnicodeString result;msgFormat.format(args, 2, result, status);std::string resultUtf8;result.toUTF8String(resultUtf8);std::cout << "Message: " << resultUtf8 << std::endl;// クリーンアップdelete dateFormatJa;delete dateFormatEn;delete currencyJa;delete currencyEn;delete pluralRulesEn;return 0;}
CMakeLists.txt (ICU):
cmake_minimum_required(VERSION 3.10)project(icu_example)set(CMAKE_CXX_STANDARD 17)# ICU を探すfind_package(ICU REQUIRED COMPONENTS uc i18n)add_executable(icu_example main.cpp)target_include_directories(icu_example PRIVATE ${ICU_INCLUDE_DIRS})target_link_libraries(icu_example PRIVATE ${ICU_LIBRARIES})
3. Boost.Locale (C++標準風API)
#include <boost/locale.hpp>#include <iostream>using namespace boost::locale;int main() {// ロケールジェネレーターgenerator gen;// サポートロケール追加gen.add_messages_path("./locale");gen.add_messages_domain("myapp");// ロケール設定std::locale::global(gen("ja_JP.UTF-8"));std::cout.imbue(std::locale());// 翻訳std::cout << translate("Welcome!") << std::endl;std::cout << translate("Hello, {1}!").str("田中") << std::endl;// 複数形std::cout << format(translate("You have {1} message","You have {1} messages",5)) % 5<< std::endl;// 日付フォーマットauto now = std::time(nullptr);std::cout << as::date << std::put_time(std::localtime(&now), "%x")<< std::endl;// 通貨std::cout << as::currency << 1234.56 << std::endl;return 0;}
ベストプラクティス
.NET
- IStringLocalizer 使用: ResourceManager より推奨
- リソース配置: コントローラー/ビュー別に整理
- ハードコード回避: すべての文字列をリソース化
- 文化フォールバック:
ja-JP→ja→ デフォルト - キャッシング: パフォーマンス向上
- データアノテーション: バリデーションメッセージも国際化
C++
- gettext 優先: 翻訳管理に最適
- ICU 併用: 日付・通貨・複数形はICU
- UTF-8 統一: すべての文字列をUTF-8
- マクロ使用:
_()でシンプルに - コンテキスト: pgettext でキー重複回避
- 自動抽出: xgettext で翻訳文字列抽出
翻訳ワークフロー
1. 文字列抽出
.NET:
# カスタムツールで .resx から未翻訳キーを抽出dotnet run --project LocalizationTool extract --output missing.csv
C++:
# xgettext で翻訳可能文字列を抽出xgettext --keyword=_ --output=messages.pot src/**/*.cpp
2. 翻訳
- 手動翻訳: Poedit、Lokalize などのGUIツール
- 機械翻訳: DeepL/Google Translate API統合
- 翻訳サービス: Crowdin、Lokalise、Phrase
3. 品質チェック
# .NET: 重複キー検出dotnet run --project LocalizationTool validate# C++: .po ファイル検証msgfmt --check-format --check-header ja.po
4. 進捗レポート
Translation Progress====================Japanese (ja): 100% ✅ (250/250)Chinese (zh): 85% ⚠️ (213/250)Spanish (es): 60% ❌ (150/250)Missing in Chinese:- Settings.Privacy.DeleteAccount- Checkout.Payment.ApplePay...
高度な機能
複数形ルール
.NET (.resx):
<data name="ItemCount" xml:space="preserve"><value>{0} items</value></data>
C++ (gettext):
msgid "%d item"msgid_plural "%d items"msgstr[0] "%d 個のアイテム" # 日本語は単複同形
日付・通貨フォーマット
.NET:
var date = DateTime.Now;var formattedDate = date.ToString("D", CultureInfo.CurrentCulture);var price = 1234.56m;var formattedPrice = price.ToString("C", CultureInfo.CurrentCulture);// ja-JP: ¥1,235// en-US: $1,234.56
C++ (ICU):
NumberFormat* fmt = NumberFormat::createCurrencyInstance(Locale("ja_JP"), status);UnicodeString result;fmt->format(1234.56, result);// ¥1,235
ツールとユーティリティ
.NET ツール
- ResXManager - Visual Studio拡張
- Zeta Resource Editor - スタンドアロンエディター
- Lokalise.NET - APIクライアント
C++ ツール
- Poedit - .po ファイルエディター(GUI)
- gettext utilities - xgettext, msgfmt, msgmerge
- translate-toolkit - Pythonベース変換ツール
統合例
例1: ASP.NET Core Web API
ASP.NET Core Web APIに多言語対応:- API レスポンスメッセージ- バリデーションエラー- Accept-Language ヘッダー対応言語: 英語、日本語、中国語
例2: WPF デスクトップアプリ
WPF 在庫管理アプリを多言語化:- すべてのUI要素- メッセージボックス- レポート出力- ランタイム言語切り替え言語: 英語、日本語、ドイツ語、スペイン語
例3: C++ クロスプラットフォームCLI
C++ コマンドラインツールにgettext統合:- ヘルプメッセージ- エラーメッセージ- 進捗表示- 環境変数でロケール切り替え言語: 英語、日本語、フランス語
制限事項
- .NET: リソースファイルはコンパイル時埋め込み(動的追加不可)
- C++: gettext はランタイムで .mo ファイル必要
- ICU: ライブラリサイズが大きい(30MB+)
- 複数形: 言語により複数形ルールが異なる
バージョン情報
- スキルバージョン: 1.0.0
- 対応 .NET: .NET Core 3.1+, .NET 6/7/8/9
- 対応 C++: C++11 以上
- 最終更新: 2025-11-22
使用例:
ASP.NET Core MVC プロジェクトに国際化を追加:言語: 英語(デフォルト)、日本語、中国語リソース配置: Resources/機能:- すべてのビュー、コントローラー- データアノテーション- クッキーベース言語切り替え- 日付・通貨のロケール別フォーマット完全な実装コード、設定ファイル、リソースファイルを生成してください。
または
C++ デスクトップアプリケーションにgettextを統合:ライブラリ: gettext言語: 英語、日本語、ドイツ語機能:- すべてのUI文字列- エラーメッセージ- 複数形対応- CMake ビルド統合セットアップコード、翻訳ファイル、ビルドスクリプトを生成してください。
エンタープライズレベルの国際化が実装されます!