こんにちは!今回は、PHPの標準関数であるsetlocale()について詳しく解説していきます。日付や通貨、数値などのフォーマットを地域に合わせて設定できる重要な関数です!
setlocale関数とは?
setlocale()関数は、PHPのロケール(地域・言語設定)を変更する関数です。
ロケールを設定することで、日付・時刻、通貨、数値、文字列の比較などを、指定した地域の慣習に従ってフォーマットできます!
基本的な構文
setlocale(int $category, string|array $locales, string ...$rest): string|false
- $category: ロケールカテゴリ(LC_ALL、LC_TIME、LC_MONETARYなど)
- $locales: ロケール名(配列または文字列)
- $rest: 追加のロケール名(フォールバック用)
- 戻り値: 設定されたロケール名、失敗時は
false
ロケールカテゴリ
// すべてのカテゴリ
LC_ALL // すべてのロケール設定
// 個別カテゴリ
LC_COLLATE // 文字列比較
LC_CTYPE // 文字の分類と変換
LC_MONETARY // 通貨フォーマット
LC_NUMERIC // 数値フォーマット
LC_TIME // 日付・時刻フォーマット
LC_MESSAGES // システムメッセージ
基本的な使用例
シンプルな設定
// 日本語ロケールに設定
setlocale(LC_ALL, 'ja_JP.UTF-8');
// 日付をフォーマット
echo strftime('%Y年%m月%d日 %A') . "\n";
// 出力例: 2026年03月24日 火曜日
// アメリカ英語ロケールに設定
setlocale(LC_ALL, 'en_US.UTF-8');
// 日付をフォーマット
echo strftime('%B %d, %Y (%A)') . "\n";
// 出力例: March 24, 2026 (Tuesday)
複数のロケールを試す(フォールバック)
// 複数のロケールを配列で指定(最初に見つかったものが使用される)
$locale = setlocale(
LC_ALL,
['ja_JP.UTF-8', 'ja_JP', 'japanese']
);
if ($locale === false) {
echo "ロケールの設定に失敗しました\n";
} else {
echo "設定されたロケール: {$locale}\n";
}
// 可変引数で指定
setlocale(LC_ALL, 'ja_JP.UTF-8', 'ja_JP', 'japanese');
現在のロケールを取得
// 現在のロケールを取得(引数に0を渡す)
$currentLocale = setlocale(LC_ALL, 0);
echo "現在のロケール: {$currentLocale}\n";
// カテゴリごとに取得
$timeLocale = setlocale(LC_TIME, 0);
echo "時刻ロケール: {$timeLocale}\n";
カテゴリ別の設定
// 時刻だけを日本語に設定
setlocale(LC_TIME, 'ja_JP.UTF-8');
// 数値はアメリカ式に設定
setlocale(LC_NUMERIC, 'en_US.UTF-8');
// 通貨はユーロ圏に設定
setlocale(LC_MONETARY, 'de_DE.UTF-8');
実践的な使用例
例1: 多言語日付フォーマッター
class LocalizedDateFormatter {
private $originalLocale;
/**
* 日付を指定ロケールでフォーマット
*/
public static function format($timestamp, $locale, $format = '%c') {
// 元のロケールを保存
$originalLocale = setlocale(LC_TIME, 0);
// 指定ロケールに変更
$result = setlocale(LC_TIME, $locale);
if ($result === false) {
// ロケール設定失敗
setlocale(LC_TIME, $originalLocale);
return false;
}
// フォーマット
$formatted = strftime($format, $timestamp);
// ロケールを元に戻す
setlocale(LC_TIME, $originalLocale);
return $formatted;
}
/**
* 複数のロケールで日付を表示
*/
public static function formatMultiple($timestamp, $locales) {
$results = [];
foreach ($locales as $localeName => $locale) {
$formatted = self::format($timestamp, $locale, '%A, %B %d, %Y');
if ($formatted !== false) {
$results[$localeName] = $formatted;
}
}
return $results;
}
/**
* 長い日付形式
*/
public static function formatLong($timestamp, $locale) {
return self::format($timestamp, $locale, '%A, %B %d, %Y');
}
/**
* 短い日付形式
*/
public static function formatShort($timestamp, $locale) {
return self::format($timestamp, $locale, '%x');
}
/**
* 時刻形式
*/
public static function formatTime($timestamp, $locale) {
return self::format($timestamp, $locale, '%X');
}
/**
* 完全形式(日付+時刻)
*/
public static function formatFull($timestamp, $locale) {
return self::format($timestamp, $locale, '%c');
}
/**
* カスタム形式
*/
public static function formatCustom($timestamp, $locale, $format) {
return self::format($timestamp, $locale, $format);
}
}
// 使用例
echo "=== 多言語日付フォーマット ===\n";
$timestamp = time();
$locales = [
'日本語' => 'ja_JP.UTF-8',
'英語(米国)' => 'en_US.UTF-8',
'英語(英国)' => 'en_GB.UTF-8',
'フランス語' => 'fr_FR.UTF-8',
'ドイツ語' => 'de_DE.UTF-8',
'中国語' => 'zh_CN.UTF-8'
];
$results = LocalizedDateFormatter::formatMultiple($timestamp, $locales);
foreach ($results as $name => $formatted) {
echo "{$name}: {$formatted}\n";
}
echo "\n=== 様々なフォーマット ===\n";
$locale = 'ja_JP.UTF-8';
echo "長い形式: " . LocalizedDateFormatter::formatLong($timestamp, $locale) . "\n";
echo "短い形式: " . LocalizedDateFormatter::formatShort($timestamp, $locale) . "\n";
echo "時刻: " . LocalizedDateFormatter::formatTime($timestamp, $locale) . "\n";
echo "完全形式: " . LocalizedDateFormatter::formatFull($timestamp, $locale) . "\n";
echo "\n=== カスタム形式 ===\n";
echo LocalizedDateFormatter::formatCustom($timestamp, 'ja_JP.UTF-8', '%Y年%m月%d日(%a)') . "\n";
echo LocalizedDateFormatter::formatCustom($timestamp, 'en_US.UTF-8', '%B %d, %Y at %I:%M %p') . "\n";
例2: 通貨フォーマッター
class CurrencyFormatter {
/**
* 金額を指定ロケールでフォーマット
*/
public static function format($amount, $locale) {
// 元のロケールを保存
$originalLocale = setlocale(LC_MONETARY, 0);
// 指定ロケールに変更
$result = setlocale(LC_MONETARY, $locale);
if ($result === false) {
setlocale(LC_MONETARY, $originalLocale);
return false;
}
// ロケール情報を取得
$localeInfo = localeconv();
// フォーマット
$formatted = money_format('%n', $amount);
// ロケールを元に戻す
setlocale(LC_MONETARY, $originalLocale);
return [
'formatted' => $formatted,
'currency_symbol' => $localeInfo['currency_symbol'],
'decimal_point' => $localeInfo['mon_decimal_point'],
'thousands_sep' => $localeInfo['mon_thousands_sep']
];
}
/**
* 複数の通貨でフォーマット
*/
public static function formatMultipleCurrencies($amount) {
$currencies = [
'JPY (日本円)' => 'ja_JP.UTF-8',
'USD (米ドル)' => 'en_US.UTF-8',
'EUR (ユーロ)' => 'de_DE.UTF-8',
'GBP (英ポンド)' => 'en_GB.UTF-8',
'CNY (人民元)' => 'zh_CN.UTF-8'
];
$results = [];
foreach ($currencies as $name => $locale) {
$formatted = self::format($amount, $locale);
if ($formatted !== false) {
$results[$name] = $formatted;
}
}
return $results;
}
/**
* ロケール情報を取得
*/
public static function getLocaleInfo($locale) {
$originalLocale = setlocale(LC_MONETARY, 0);
setlocale(LC_MONETARY, $locale);
$info = localeconv();
setlocale(LC_MONETARY, $originalLocale);
return $info;
}
}
// 使用例
echo "=== 通貨フォーマット ===\n";
$amount = 1234567.89;
// Note: money_format()はPHP 7.4で非推奨、PHP 8.0で削除されました
// 以下は概念的な例です
echo "金額: {$amount}\n\n";
$results = CurrencyFormatter::formatMultipleCurrencies($amount);
foreach ($results as $currency => $data) {
echo "{$currency}:\n";
if (isset($data['formatted'])) {
echo " フォーマット済み: {$data['formatted']}\n";
}
echo " 通貨記号: {$data['currency_symbol']}\n";
echo " 小数点: {$data['decimal_point']}\n";
echo " 千の位区切り: {$data['thousands_sep']}\n\n";
}
echo "\n=== ロケール詳細情報(日本) ===\n";
$info = CurrencyFormatter::getLocaleInfo('ja_JP.UTF-8');
print_r($info);
例3: 数値フォーマッター
class NumberFormatter {
/**
* 数値を指定ロケールでフォーマット
*/
public static function format($number, $locale, $decimals = 2) {
// 元のロケールを保存
$originalLocale = setlocale(LC_NUMERIC, 0);
// 指定ロケールに変更
$result = setlocale(LC_NUMERIC, $locale);
if ($result === false) {
setlocale(LC_NUMERIC, $originalLocale);
return false;
}
// ロケール情報を取得
$localeInfo = localeconv();
// 数値をフォーマット
$formatted = number_format(
$number,
$decimals,
$localeInfo['decimal_point'],
$localeInfo['thousands_sep']
);
// ロケールを元に戻す
setlocale(LC_NUMERIC, $originalLocale);
return $formatted;
}
/**
* 複数のロケールで数値を表示
*/
public static function formatMultiple($number) {
$locales = [
'日本' => 'ja_JP.UTF-8',
'アメリカ' => 'en_US.UTF-8',
'ドイツ' => 'de_DE.UTF-8',
'フランス' => 'fr_FR.UTF-8'
];
$results = [];
foreach ($locales as $name => $locale) {
$formatted = self::format($number, $locale);
if ($formatted !== false) {
$results[$name] = $formatted;
}
}
return $results;
}
/**
* パーセンテージをフォーマット
*/
public static function formatPercentage($number, $locale) {
$formatted = self::format($number, $locale, 2);
return $formatted !== false ? $formatted . '%' : false;
}
}
// 使用例
echo "=== 数値フォーマット ===\n";
$number = 1234567.89;
echo "元の数値: {$number}\n\n";
$results = NumberFormatter::formatMultiple($number);
foreach ($results as $locale => $formatted) {
echo "{$locale}: {$formatted}\n";
}
echo "\n=== パーセンテージ ===\n";
echo "日本: " . NumberFormatter::formatPercentage(45.67, 'ja_JP.UTF-8') . "\n";
echo "アメリカ: " . NumberFormatter::formatPercentage(45.67, 'en_US.UTF-8') . "\n";
例4: 文字列比較(ロケール依存)
class LocalizedStringComparator {
/**
* ロケールに基づいて文字列を比較
*/
public static function compare($str1, $str2, $locale) {
// 元のロケールを保存
$originalLocale = setlocale(LC_COLLATE, 0);
// 指定ロケールに変更
setlocale(LC_COLLATE, $locale);
// 比較
$result = strcoll($str1, $str2);
// ロケールを元に戻す
setlocale(LC_COLLATE, $originalLocale);
return $result;
}
/**
* ロケールに基づいて配列をソート
*/
public static function sort($array, $locale) {
// 元のロケールを保存
$originalLocale = setlocale(LC_COLLATE, 0);
// 指定ロケールに変更
setlocale(LC_COLLATE, $locale);
// ソート
usort($array, function($a, $b) {
return strcoll($a, $b);
});
// ロケールを元に戻す
setlocale(LC_COLLATE, $originalLocale);
return $array;
}
/**
* 複数のロケールでソート結果を比較
*/
public static function sortMultiple($array, $locales) {
$results = [];
foreach ($locales as $name => $locale) {
$results[$name] = self::sort($array, $locale);
}
return $results;
}
}
// 使用例
echo "=== ロケール依存の文字列比較 ===\n";
// 日本語の文字列
$strings = ['あいうえお', 'かきくけこ', 'さしすせそ', 'たちつてと'];
$locales = [
'日本語' => 'ja_JP.UTF-8',
'C(デフォルト)' => 'C'
];
$results = LocalizedStringComparator::sortMultiple($strings, $locales);
foreach ($results as $locale => $sorted) {
echo "\n{$locale}:\n";
foreach ($sorted as $str) {
echo " {$str}\n";
}
}
// アルファベットの比較
echo "\n=== アルファベットの比較 ===\n";
$words = ['école', 'zebra', 'apple', 'Über'];
$results = LocalizedStringComparator::sortMultiple($words, [
'フランス語' => 'fr_FR.UTF-8',
'ドイツ語' => 'de_DE.UTF-8',
'アメリカ英語' => 'en_US.UTF-8'
]);
foreach ($results as $locale => $sorted) {
echo "\n{$locale}:\n";
echo " " . implode(', ', $sorted) . "\n";
}
例5: ロケールマネージャー
class LocaleManager {
private static $stack = [];
/**
* 現在のロケールを保存してスタックにプッシュ
*/
public static function push($category = LC_ALL) {
$current = setlocale($category, 0);
self::$stack[] = [
'category' => $category,
'locale' => $current
];
return $current;
}
/**
* スタックからロケールをポップして復元
*/
public static function pop() {
if (empty(self::$stack)) {
return false;
}
$saved = array_pop(self::$stack);
return setlocale($saved['category'], $saved['locale']);
}
/**
* 一時的にロケールを変更して処理を実行
*/
public static function withLocale($locale, $callback, $category = LC_ALL) {
self::push($category);
setlocale($category, $locale);
try {
$result = $callback();
} finally {
self::pop();
}
return $result;
}
/**
* 利用可能なロケールを検出
*/
public static function getAvailableLocales($testLocales) {
$available = [];
$originalLocale = setlocale(LC_ALL, 0);
foreach ($testLocales as $locale) {
if (setlocale(LC_ALL, $locale) !== false) {
$available[] = $locale;
}
}
setlocale(LC_ALL, $originalLocale);
return $available;
}
/**
* ロケール情報を取得
*/
public static function getInfo($category = LC_ALL) {
return [
'current_locale' => setlocale($category, 0),
'category' => self::getCategoryName($category),
'locale_conv' => localeconv()
];
}
/**
* カテゴリ名を取得
*/
private static function getCategoryName($category) {
$names = [
LC_ALL => 'LC_ALL',
LC_COLLATE => 'LC_COLLATE',
LC_CTYPE => 'LC_CTYPE',
LC_MONETARY => 'LC_MONETARY',
LC_NUMERIC => 'LC_NUMERIC',
LC_TIME => 'LC_TIME',
LC_MESSAGES => 'LC_MESSAGES'
];
return $names[$category] ?? 'UNKNOWN';
}
}
// 使用例
echo "=== ロケールマネージャー ===\n";
// 現在のロケールを保存
$originalLocale = LocaleManager::push(LC_TIME);
echo "元のロケール: {$originalLocale}\n";
// 日本語に変更
setlocale(LC_TIME, 'ja_JP.UTF-8');
echo "変更後: " . strftime('%Y年%m月%d日') . "\n";
// 元に戻す
LocaleManager::pop();
echo "復元後のロケール: " . setlocale(LC_TIME, 0) . "\n";
// withLocaleを使用
echo "\n=== withLocale使用例 ===\n";
$result = LocaleManager::withLocale('ja_JP.UTF-8', function() {
return strftime('%Y年%m月%d日 %A');
}, LC_TIME);
echo "一時的な日本語: {$result}\n";
echo "現在のロケール: " . setlocale(LC_TIME, 0) . "\n";
// 利用可能なロケールを検出
echo "\n=== 利用可能なロケール ===\n";
$testLocales = [
'ja_JP.UTF-8',
'en_US.UTF-8',
'fr_FR.UTF-8',
'de_DE.UTF-8',
'invalid_locale'
];
$available = LocaleManager::getAvailableLocales($testLocales);
echo "利用可能: " . implode(', ', $available) . "\n";
// ロケール情報を取得
echo "\n=== ロケール情報 ===\n";
$info = LocaleManager::getInfo(LC_NUMERIC);
print_r($info);
例6: 国際化ヘルパー
class I18nHelper {
/**
* ユーザーの言語設定に基づいてロケールを設定
*/
public static function setUserLocale($languageCode) {
$localeMap = [
'ja' => 'ja_JP.UTF-8',
'en' => 'en_US.UTF-8',
'fr' => 'fr_FR.UTF-8',
'de' => 'de_DE.UTF-8',
'es' => 'es_ES.UTF-8',
'zh' => 'zh_CN.UTF-8',
'ko' => 'ko_KR.UTF-8'
];
$locale = $localeMap[$languageCode] ?? 'en_US.UTF-8';
return setlocale(LC_ALL, $locale);
}
/**
* ブラウザの言語設定からロケールを検出
*/
public static function detectFromBrowser() {
if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
return 'en_US.UTF-8';
}
$languages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$primaryLang = strtolower(substr($languages[0], 0, 2));
return self::setUserLocale($primaryLang);
}
/**
* 地域別の挨拶を取得
*/
public static function getGreeting($locale) {
$originalLocale = setlocale(LC_ALL, 0);
setlocale(LC_ALL, $locale);
$greetings = [
'ja_JP' => 'こんにちは',
'en_US' => 'Hello',
'fr_FR' => 'Bonjour',
'de_DE' => 'Guten Tag',
'es_ES' => 'Hola',
'zh_CN' => '你好',
'ko_KR' => '안녕하세요'
];
$currentLocale = setlocale(LC_ALL, 0);
$localePrefix = substr($currentLocale, 0, 5);
$greeting = $greetings[$localePrefix] ?? $greetings['en_US'];
setlocale(LC_ALL, $originalLocale);
return $greeting;
}
/**
* ロケールに応じた日付表示
*/
public static function formatLocalizedDate($timestamp, $languageCode) {
self::setUserLocale($languageCode);
$formats = [
'ja' => '%Y年%m月%d日(%a)',
'en' => '%B %d, %Y (%a)',
'fr' => '%d %B %Y (%a)',
'de' => '%d. %B %Y (%a)'
];
$format = $formats[$languageCode] ?? $formats['en'];
return strftime($format, $timestamp);
}
}
// 使用例
echo "=== 国際化ヘルパー ===\n";
// 言語コードからロケール設定
$languages = ['ja', 'en', 'fr', 'de'];
foreach ($languages as $lang) {
$locale = I18nHelper::setUserLocale($lang);
$greeting = I18nHelper::getGreeting($locale);
$date = I18nHelper::formatLocalizedDate(time(), $lang);
echo "{$lang} ({$locale}):\n";
echo " 挨拶: {$greeting}\n";
echo " 日付: {$date}\n\n";
}
注意点と制限事項
// ロケールの利用可能性はシステムに依存
$result = setlocale(LC_ALL, 'ja_JP.UTF-8');
if ($result === false) {
echo "このロケールはシステムにインストールされていません\n";
// フォールバック
setlocale(LC_ALL, 'C'); // Cロケール(最小限の標準ロケール)
}
// マルチスレッド環境での注意
// setlocale()はプロセス全体に影響するため、
// マルチスレッド環境では問題が発生する可能性がある
// strftime()はPHP 8.1で非推奨
// 代わりにIntlDateFormatterやDateTimeクラスの使用を推奨
代替手段(IntlDateFormatter)
// より推奨される方法(PHP 5.3+)
$formatter = new IntlDateFormatter(
'ja_JP',
IntlDateFormatter::LONG,
IntlDateFormatter::NONE
);
echo $formatter->format(time()) . "\n";
// 通貨フォーマット
$formatter = new NumberFormatter('ja_JP', NumberFormatter::CURRENCY);
echo $formatter->formatCurrency(1234567, 'JPY') . "\n";
まとめ
setlocale()関数の特徴をまとめると:
できること:
- 地域・言語設定の変更
- 日付・時刻のローカライズ
- 通貨・数値のフォーマット
- 文字列比較の調整
推奨される使用場面:
- 多言語対応アプリケーション
- 国際化(i18n)
- 地域別フォーマット
- 日付・通貨表示
カテゴリ:
LC_ALL: すべてLC_TIME: 日付・時刻LC_MONETARY: 通貨LC_NUMERIC: 数値LC_COLLATE: 文字列比較
注意点:
- システムにロケールがインストールされている必要がある
- プロセス全体に影響する
- マルチスレッド環境では注意が必要
strftime()はPHP 8.1で非推奨
代替手段:
IntlDateFormatter: 日付フォーマットNumberFormatter: 数値・通貨フォーマットCollator: 文字列比較
使い分け:
// シンプルな日付表示: setlocale() + strftime()
setlocale(LC_TIME, 'ja_JP.UTF-8');
echo strftime('%Y年%m月%d日');
// より高機能: IntlDateFormatter
$formatter = new IntlDateFormatter('ja_JP', IntlDateFormatter::LONG, IntlDateFormatter::NONE);
echo $formatter->format(time());
setlocale()は、地域に応じたフォーマットを簡単に実現できる便利な関数ですが、システム依存性が高いため、新しいプロジェクトではIntl拡張の使用を検討しましょう!
