Skip to content

Localization

You can customize translations:

php
// we recommend to use custom language name/variant
// rather than overriding an existing language
// to avoid conflict such as "en_Boring" in the example below:
$boringLanguage = 'en_Boring';
$translator = \Carbon\Translator::get($boringLanguage);
$translator->setTranslations([
	'day' => ':count boring day|:count boring days',
]);
// as this language starts with "en_" it will inherit from the locale "en"

$date1 = Carbon::create(2018, 1, 1, 0, 0, 0);
$date2 = Carbon::create(2018, 1, 4, 4, 0, 0);


echo $date1->locale($boringLanguage)->diffForHumans($date2);    // 3 boring days before


$translator->setTranslations([
	'before' => function ($time) {
		return '['.strtoupper($time).']';
	},
]);


echo $date1->locale($boringLanguage)->diffForHumans($date2);    // [3 BORING DAYS]

You can use fallback locales by passing in order multiple ones to locale():

php
\Carbon\Translator::get('xx')->setTranslations([
	'day' => ':count Xday',
]);
\Carbon\Translator::get('xy')->setTranslations([
	'day' => ':count Yday',
	'hour' => ':count Yhour',
]);

$date = Carbon::now()->locale('xx', 'xy', 'es')->sub('3 days 6 hours 40 minutes');


echo $date->ago(['parts' => 3]);    // hace 3 Xday 6 Yhour 40 minutos

In the example above, it will try to find translations in "xx" in priority, then in "xy" if missing, then in "es", so here, you get "Xday" from "xx", "Yhour" from "xy", and "hace" and "minutos" from "es".

Note that you can also use an other translator with Carbon::setTranslator($custom) as long as the given translator implements Symfony\Component\Translation\TranslatorInterface. And you can get the global default translator using Carbon::getTranslator() (and Carbon::setFallbackLocale($custom) and Carbon::getFallbackLocale() for the fallback locale, setFallbackLocale can be called multiple times to get multiple fallback locales) but as those method will change the behavior globally (including third-party libraries you may have in your app), it might cause unexpected results. You should rather customize translation using custom locales as in the example above.

Carbon embed a default translator that extends Symfony\\Component\\Translation\\Translator You can check here the methods we added to it.

You can check what's supported with the following methods:

php
echo implode(', ', array_slice(Carbon::getAvailableLocales(), 0, 3)).'...';    // aa, aa_DJ, aa_ER...

// Support diff syntax (before, after, from now, ago)
var_dump(Carbon::localeHasDiffSyntax('en'));                                   // bool(true)
var_dump(Carbon::localeHasDiffSyntax('zh_TW'));                                // bool(true)
// Support 1-day diff words (just now, yesterday, tomorrow)
var_dump(Carbon::localeHasDiffOneDayWords('en'));                              // bool(true)
var_dump(Carbon::localeHasDiffOneDayWords('zh_TW'));                           // bool(true)
// Support 2-days diff words (before yesterday, after tomorrow)
var_dump(Carbon::localeHasDiffTwoDayWords('en'));                              // bool(true)
var_dump(Carbon::localeHasDiffTwoDayWords('zh_TW'));                           // bool(false)
// Support short units (1y = 1 year, 1mo = 1 month, etc.)
var_dump(Carbon::localeHasShortUnits('en'));                                   // bool(true)
var_dump(Carbon::localeHasShortUnits('zh_TW'));                                // bool(false)
// Support period syntax (X times, every X, from X, to X)
var_dump(Carbon::localeHasPeriodSyntax('en'));                                 // bool(true)
var_dump(Carbon::localeHasPeriodSyntax('zh_TW'));                              // bool(false)

So, here is the new recommended way to handle internationalization with Carbon.

php
$date = Carbon::now()->locale('fr_FR');

echo $date->locale();             // fr_FR
echo "\n";                       
echo $date->diffForHumans();      // il y a 0 seconde
echo "\n";                       
echo $date->monthName;            // décembre
echo "\n";                       
echo $date->isoFormat('LLLL');    // vendredi 26 décembre 2025 13:19

The ->locale() method only change the language for the current instance and has precedence over global settings. We recommend you this approach so you can't have conflict with other places or third-party libraries that could use Carbon. Nevertheless, to avoid calling ->locale() each time, you can use factories.

php
// Let say Martin from Paris and John from Chicago play chess
$martinDateFactory = new Factory([
	'locale' => 'fr_FR',
	'timezone' => 'Europe/Paris',
]);
$johnDateFactory = new Factory([
	'locale' => 'en_US',
	'timezone' => 'America/Chicago',
]);
// Each one will see date in his own language and timezone

// When Martin moves, we display things in French, but we notify John in English:
$gameStart = Carbon::parse('2018-06-15 12:34:00', 'UTC');
$move = Carbon::now('UTC');
$toDisplay = $martinDateFactory->make($gameStart)->isoFormat('lll')."\n".
$martinDateFactory->make($move)->calendar()."\n";
$notificationForJohn = $johnDateFactory->make($gameStart)->isoFormat('lll')."\n".
$johnDateFactory->make($move)->calendar()."\n";
echo $toDisplay;             
/*
15 juin 2018 14:34
Aujourd’hui à 14:19
*/

echo $notificationForJohn;   
/*
Jun 15, 2018 7:34 AM
Today at 7:19 AM
*/

You can call any static Carbon method on a factory (make, now, yesterday, tomorrow, parse, create, etc.) Factory (and FactoryImmutable that generates CarbonImmutable instances) are the best way to keep things organized and isolated. As often as possible we recommend you to work with UTC dates, then apply locally (or with a factory) the timezone and the language before displaying dates to the user.

What factory actually do is using the method name as static constructor then call settings() method which is a way to group in one call settings of locale, timezone, months/year overflow, etc. (See references for complete list.)

php
$factory = new Factory([
	'locale' => 'fr_FR',
	'timezone' => 'Europe/Paris',
]);
$factory->now(); // You can recall $factory as needed to generate new instances with same settings
// is equivalent to:
Carbon::now()->settings([
	'locale' => 'fr_FR',
	'timezone' => 'Europe/Paris',
]);
// Important note: timezone setting calls ->shiftTimezone() and not ->setTimezone(),
// It means it does not just set the timezone, but shift the time too:

echo Carbon::today()->setTimezone('Asia/Tokyo')->format('d/m G\h e');      // 26/12 9h Asia/Tokyo
echo "\n";                                                                
echo Carbon::today()->shiftTimezone('Asia/Tokyo')->format('d/m G\h e');    // 26/12 0h Asia/Tokyo

// You can find back which factory created a given object:
$a = $factory->now();
$b = Carbon::now();

var_dump($a->getClock()->unwrap() === $factory);                           // bool(true)
var_dump($b->getClock());                                                  // NULL

settings() also allow to pass local macros:

php
$date = Carbon::parse('Today 12:34:56')->settings([
	'macros' => [
		'lastSecondDigit' => fn () => self::this()->second % 10,
	],
]);

echo $date->lastSecondDigit();    // 6
var_dump($date->hasLocalMacro('lastSecondDigit')); // bool(true)
// You can also retrieve the macro closure using ->getLocalMacro('lastSecondDigit')

Factory settings can be changed afterward with setSettings(array $settings) or to merge new settings with existing ones mergeSettings(array $settings) and the class to generate can be initialized as the second argument of the construct then changed later with setClassName(string $className).

php
$factory = new Factory(['locale' => 'ja'], CarbonImmutable::class);

var_dump($factory->now()->locale); // string(2) "ja"
var_dump(get_class($factory->now())); // string(22) "Carbon\CarbonImmutable"

class MyCustomCarbonSubClass extends Carbon { /* ... */ }
$factory
	->setSettings(['locale' => 'zh_CN'])
	->setClassName(MyCustomCarbonSubClass::class);

var_dump($factory->now()->locale); // string(5) "zh_CN"
var_dump(get_class($factory->now())); // string(22) "MyCustomCarbonSubClass"

Previously there was Carbon::setLocale that set globally the locale. But as for our other static setters, we highly discourage you to use it. It breaks the principle of isolation because the configuration will apply for every class that uses Carbon.

->isoFormat(string $format): string use ISO format rather than PHP-specific format and use inner translations rather than language packages you need to install on every machine where you deploy your application. isoFormat method is compatible with momentjs format method, it means you can use same format strings as you may have used in moment from front-end or node.js. Here are some examples:

php
$date = Carbon::parse('2018-06-15 17:34:15.984512', 'UTC');
echo $date->isoFormat('MMMM Do YYYY, h:mm:ss a');    // June 15th 2018, 5:34:15 pm
echo "\n";                                          
echo $date->isoFormat('dddd');                       // Friday
echo "\n";                                          
echo $date->isoFormat('MMM Do YY');                  // Jun 15th 18
echo "\n";                                          
echo $date->isoFormat('YYYY [escaped] YYYY');        // 2018 escaped 2018

You can also create date from ISO formatted strings:

php
$date = Carbon::createFromIsoFormat('!YYYY-MMMM-D h:mm:ss a', '2019-January-3 6:33:24 pm', 'UTC');
echo $date->isoFormat('M/D/YY HH:mm');    // 1/3/19 18:33

->isoFormat use contextualized methods for day names and month names as they can have multiple forms in some languages, see the following examples:

php
$date = Carbon::parse('2018-03-16')->locale('uk');
echo $date->getTranslatedDayName('[в] dddd');                       // п’ятницю
// By providing a context, we're saying translate day name like in a format such as [в] dddd
// So the context itself has to be translated first consistently.
echo "\n";                                                          
echo $date->getTranslatedDayName('[наступної] dddd');       // п’ятниці
echo "\n";                                                          
echo $date->getTranslatedDayName('dddd, MMM');                       // п’ятниця
echo "\n";                                                          
// The same goes for short/minified variants:
echo $date->getTranslatedShortDayName('[наступної] dd');    // пт
echo "\n";                                                          
echo $date->getTranslatedMinDayName('[наступної] ddd');     // пт
echo "\n";                                                          

// And the same goes for months
$date->locale('ru');
echo $date->getTranslatedMonthName('Do MMMM');                       // марта
echo "\n";                                                          
echo $date->getTranslatedMonthName('MMMM YYYY');                     // март
echo "\n";                                                          
// Short variant
echo $date->getTranslatedShortMonthName('Do MMM');                   // мар
echo "\n";                                                          
echo $date->getTranslatedShortMonthName('MMM YYYY');                 // мар
echo "\n";                                                          

// And so you can force a different context to get those variants:
echo $date->isoFormat('Do MMMM');                                    // 16-го марта
echo "\n";                                                          
echo $date->isoFormat('MMMM YYYY');                                  // март 2018
echo "\n";                                                          
echo $date->isoFormat('Do MMMM', 'MMMM YYYY');                       // 16-го март
echo "\n";                                                          
echo $date->isoFormat('MMMM YYYY', 'Do MMMM');                       // марта 2018
echo "\n";

Here is the complete list of available replacements (examples given with $date = Carbon::parse('2017-01-05 17:04:05.084512');):

CodeExampleDescription
OD5Day number with alternative numbers such as 三 for 3 if locale is ja_JP
OM1Month number with alternative numbers such as ၀၂ for 2 if locale is my_MM
OY2017Year number with alternative numbers such as ۱۹۹۸ for 1998 if locale is fa
OH1724-hours number with alternative numbers such as ႑႓ for 13 if locale is shn_MM
Oh512-hours number with alternative numbers such as 十一 for 11 if locale is lzh_TW
Om4Minute number with alternative numbers such as ୫୭ for 57 if locale is or
Os5Second number with alternative numbers such as 十五 for 15 if locale is ja_JP
D5Day of month number (from 1 to 31)
DD05Day of month number with trailing zero (from 01 to 31)
Do5thDay of month with ordinal suffix (from 1st to 31th), translatable
d4Day of week number (from 0 (Sunday) to 6 (Saturday))
ddThMinified day name (from Su to Sa), translatable
dddThuShort day name (from Sun to Sat), translatable
ddddThursdayDay name (from Sunday to Saturday), translatable
DDD5Day of year number (from 1 to 366)
DDDD005Day of year number with trailing zeros (3 digits, from 001 to 366)
DDDo5thDay of year number with ordinal suffix (from 1st to 366th), translatable
e4Day of week number (from 0 (Sunday) to 6 (Saturday)), similar to "d" but this one is translatable (takes first day of week of the current locale)
E4Day of week number (from 1 (Monday) to 7 (Sunday))
H17Hour from 0 to 23
HH17Hour with trailing zero from 00 to 23
h5Hour from 0 to 12
hh05Hour with trailing zero from 00 to 12
k17Hour from 1 to 24
kk17Hour with trailing zero from 01 to 24
m4Minute from 0 to 59
mm04Minute with trailing zero from 00 to 59
apmMeridiem am/pm
APMMeridiem AM/PM
s5Second from 0 to 59
ss05Second with trailing zero from 00 to 59
S0Second tenth
SS08Second hundredth (on 2 digits with trailing zero)
SSS084Millisecond (on 3 digits with trailing zeros)
SSSS0845Second ten thousandth (on 4 digits with trailing zeros)
SSSSS08451Second hundred thousandth (on 5 digits with trailing zeros)
SSSSSS084512Microsecond (on 6 digits with trailing zeros)
SSSSSSS0845120Second ten millionth (on 7 digits with trailing zeros)
SSSSSSSS08451200Second hundred millionth (on 8 digits with trailing zeros)
SSSSSSSSS084512000Nanosecond (on 9 digits with trailing zeros)
M1Month from 1 to 12
MM01Month with trailing zero from 01 to 12
MMMJanShort month name, translatable
MMMMJanuaryMonth name, translatable
Mo1stMonth with ordinal suffix from 1st to 12th, translatable
Q1Quarter from 1 to 4
Qo1stQuarter with ordinal suffix from 1st to 4th, translatable
G2017ISO week year (see <a href="https://en.wikipedia.org/wiki/ISO_week_date" target="_blank">ISO week date</a>)
GG2017ISO week year (on 2 digits with trailing zero)
GGG2017ISO week year (on 3 digits with trailing zeros)
GGGG2017ISO week year (on 4 digits with trailing zeros)
GGGGG02017ISO week year (on 5 digits with trailing zeros)
g2017Week year according to locale settings, translatable
gg2017Week year according to locale settings (on 2 digits with trailing zero), translatable
ggg2017Week year according to locale settings (on 3 digits with trailing zeros), translatable
gggg2017Week year according to locale settings (on 4 digits with trailing zeros), translatable
ggggg02017Week year according to locale settings (on 5 digits with trailing zeros), translatable
W1ISO week number in the year (see <a href="https://en.wikipedia.org/wiki/ISO_week_date" target="_blank">ISO week date</a>)
WW01ISO week number in the year (on 2 digits with trailing zero)
Wo1stISO week number in the year with ordinal suffix, translatable
w2Week number in the year according to locale settings, translatable
ww02Week number in the year according to locale settings (on 2 digits with trailing zero)
wo2ndWeek number in the year according to locale settings with ordinal suffix, translatable
x1483635845085Millisecond-precision timestamp (same as <code>date.getTime()</code> in JavaScript)
X1483635845Timestamp (number of seconds since 1970-01-01)
Y2017Full year from -9999 to 9999
YY17Year on 2 digits from 00 to 99
YYYY2017Year on 4 digits from 0000 to 9999
YYYYY02017Year on 5 digits from 00000 to 09999
YYYYYY+002017Year on 5 digits with sign from -09999 to +09999
zUTCAbbreviated time zone name
zzUTCTime zone name
Z+00:00Time zone offset HH:mm
ZZ+0000Time zone offset HHmm

Some macro-formats are also available. Here are examples of each in some languages:

Codeenfrjahr
LT
h:mm A
5:04 PM
HH:mm
17:04
HH:mm
17:04
H:mm
17:04
LTS
h:mm:ss A
5:04:05 PM
HH:mm:ss
17:04:05
HH:mm:ss
17:04:05
H:mm:ss
17:04:05
L

l
MM/DD/YYYY
01/05/2017
1/5/2017
DD/MM/YYYY
05/01/2017
5/1/2017
YYYY/MM/DD
2017/01/05
2017/1/5
D. M. YYYY.
5. 1. 2017.
5. 1. 2017.
LL

ll
MMMM D, YYYY
January 5, 2017
Jan 5, 2017
D MMMM YYYY
5 janvier 2017
5 janv. 2017
YYYY年M月D日
2017年1月5日
2017年1月5日
D. MMMM YYYY.
5. siječnja 2017.
5. sij. 2017.
LLL

lll
MMMM D, YYYY h:mm A
January 5, 2017 5:04 PM
Jan 5, 2017 5:04 PM
D MMMM YYYY HH:mm
5 janvier 2017 17:04
5 janv. 2017 17:04
YYYY年M月D日 HH:mm
2017年1月5日 17:04
2017年1月5日 17:04
D. MMMM YYYY. H:mm
5. siječnja 2017. 17:04
5. sij. 2017. 17:04
LLLL

llll
dddd, MMMM D, YYYY h:mm A
Thursday, January 5, 2017 5:04 PM
Thu, Jan 5, 2017 5:04 PM
dddd D MMMM YYYY HH:mm
jeudi 5 janvier 2017 17:04
jeu. 5 janv. 2017 17:04
YYYY年M月D日 dddd HH:mm
2017年1月5日 木曜日 17:04
2017年1月5日 木 17:04
dddd, D. MMMM YYYY. H:mm
četvrtak, 5. siječnja 2017. 17:04
čet., 5. sij. 2017. 17:04
l
1/5/2017
5/1/2017
2017/1/5
5. 1. 2017.
ll
Jan 5, 2017
5 janv. 2017
2017年1月5日
5. sij. 2017.
lll
Jan 5, 2017 5:04 PM
5 janv. 2017 17:04
2017年1月5日 17:04
5. sij. 2017. 17:04
llll
Thu, Jan 5, 2017 5:04 PM
jeu. 5 janv. 2017 17:04
2017年1月5日 木 17:04
čet., 5. sij. 2017. 17:04

When you use macro-formats with createFromIsoFormat you can specify a locale to select which language the macro-format should be searched in.

php
$date = Carbon::createFromIsoFormat('LLLL', 'Monday 11 March 2019 16:28', null, 'fr');
echo $date->isoFormat('M/D/YY HH:mm');    // 3/11/19 16:28

Another usefull translated method is calendar($referenceTime = null, array $formats = []): string:

php
$date = CarbonImmutable::now();
echo $date->calendar();                                       // Today at 1:19 PM
echo "\n";                                                   
echo $date->sub('1 day 3 hours')->calendar();                 // Yesterday at 10:19 AM
echo "\n";                                                   
echo $date->sub('3 days 10 hours 23 minutes')->calendar();    // Last Tuesday at 2:56 AM
echo "\n";                                                   
echo $date->sub('8 days')->calendar();                        // 12/18/2025
echo "\n";                                                   
echo $date->add('1 day 3 hours')->calendar();                 // Tomorrow at 4:19 PM
echo "\n";                                                   
echo $date->add('3 days 10 hours 23 minutes')->calendar();    // Monday at 11:42 PM
echo "\n";                                                   
echo $date->add('8 days')->calendar();                        // 01/03/2026
echo "\n";                                                   
echo $date->locale('fr')->calendar();                         // Aujourd’hui à 13:19

If you know momentjs, then it works the same way. You can pass a reference date as second argument, else now is used. And you can customize one or more formats using the second argument (formats to pass as array keys are: sameDay, nextDay, nextWeek, lastDay, lastWeek and sameElse):

php
$date1 = CarbonImmutable::parse('2018-01-01 12:00:00');
$date2 = CarbonImmutable::parse('2018-01-02 8:00:00');

echo $date1->calendar($date2, [
	'lastDay' => '[Previous day at] LT',
]);    // Previous day at 12:00 PM

Click here to get an overview of the 280 locales (and 823 regional variants) supported by the last Carbon version.

If you can add missing translations or missing languages, please go to translation tool, your help is welcome.

Note that if you use Laravel, the locale will be automatically set according to current last App:setLocale execution. So diffForHumans, isoFormat, translatedFormat and localized properties such as ->dayName or ->monthName will be localized transparently.

All Carbon, CarbonImmutable, CarbonInterval or CarbonPeriod instances are linked by default to a Carbon\Translator instance handled by FactoryImmutable::getDefaultInstance() (The one changing when calling the static method ::setLocale() on one of those classes). You can get and/or change it using getLocalTranslator()/setLocalTranslator(Translator $translator).

If you prefer the date() pattern, you can use translatedFormat() which works like format() but translate the string using the current locale.

php
$date = Carbon::parse('2018-03-16 15:45')->locale('uk');

echo $date->translatedFormat('g:i a l jS F Y');    // 3:45 дня п’ятниця 16-го березня 2018

Be warned that some letters like W are not supported because they are not safely translatable and translatedFormat offers shorter syntax but less possibilities than isoFormat().

You can customize the behavior of the format() method to use any other method or a custom one instead of the native method from the PHP DateTime class:

php
$date = Carbon::parse('2018-03-16 15:45')->locale('ja');

echo $date->format('g:i a l jS F Y');    // 3:45 pm Friday 16th March 2018
echo "\n";                              

$date->settings(['formatFunction' => 'translatedFormat']);

echo $date->format('g:i a l jS F Y');    // 3:45 午後 金曜日 16日 3月 2018
echo "\n";                              

$date->settings(['formatFunction' => 'isoFormat']);

echo $date->format('LL');                // 2018年3月16日
echo "\n";                              

// When you set a custom format() method you still can access the native method using rawFormat()
echo $date->rawFormat('D');              // Fri

You can translate a string from a language to another using dates translations available in Carbon:

php
echo Carbon::translateTimeString('mercredi 8 juillet', 'fr', 'nl');                                                                                  // woensdag 8 juli

echo "\n";                                                                                                                                          

// You can select translations to use among available constants:
// - CarbonInterface::TRANSLATE_MONTHS
// - CarbonInterface::TRANSLATE_DAYS
// - CarbonInterface::TRANSLATE_UNITS
// - CarbonInterface::TRANSLATE_MERIDIEM
// - CarbonInterface::TRANSLATE_ALL (all above)
// You can combine them with pipes: like below (translate units and days but not months and meridiem):
echo Carbon::translateTimeString('mercredi 8 juillet + 3 jours', 'fr', 'nl', CarbonInterface::TRANSLATE_DAYS | CarbonInterface::TRANSLATE_UNITS);    // woensdag 8 juillet + 3 dagen

If input locale is not specified, Carbon::getLocale() is used instead. If output locale is not specified, "en" is used instead. You also can translate using the locale of the instance with:

php
echo Carbon::now()->locale('fr')->translateTimeStringTo('mercredi 8 juillet + 3 jours', 'nl');    // woensdag 8 juli + 3 dagen

You can use strings in any language directly to create a date object with parseFromLocale:

php
$date = Carbon::parseFromLocale('mercredi 6 mars 2019 + 3 jours', 'fr', 'UTC'); // timezone is optional
// 'fr' stands for French but can be replaced with any locale code.
// if you don't pass the locale parameter, Carbon::getLocale() (current global locale) is used.

echo $date->isoFormat('LLLL');    // Saturday, March 9, 2019 12:00 AM

You can also use "today", "today at 8:00", "yesterday", "after tomorrow", etc. equivalents in the given language.

Or with custom format using createFromLocaleFormat (use the date() pattern for replacements):

php
$date = Carbon::createFromLocaleFormat('!d/F/y', 'fr', '25/Août/19', 'Europe/Paris'); // timezone is optional

echo $date->isoFormat('LLLL');    // Sunday, August 25, 2019 12:00 AM

The equivalent method using ISO format is createFromLocaleIsoFormat:

php
$date = Carbon::createFromLocaleIsoFormat('!DD/MMMM/YY', 'fr', '25/Août/19', 'Europe/Paris'); // timezone is optional

echo $date->isoFormat('LLLL');    // Sunday, August 25, 2019 12:00 AM

To get some interesting info about languages (such as complete ISO name or native name, region (for example to be displayed in a languages selector), you can use getAvailableLocalesInfo.

php
$zhTwInfo = Carbon::getAvailableLocalesInfo()['zh_TW'];
$srCyrlInfo = Carbon::getAvailableLocalesInfo()['sr_Cyrl'];
$caInfo = Carbon::getAvailableLocalesInfo()['ca'];

var_dump($zhTwInfo->getId()); // string(5) "zh_TW"
var_dump($zhTwInfo->getNames());
/*
array(2) {
  ["isoName"]=>
  string(7) "Chinese"
  ["nativeName"]=>
  string(38) "中文 (Zhōngwén), 汉语, 漢語"
}
*/
var_dump($zhTwInfo->getCode()); // string(2) "zh"
var_dump($zhTwInfo->getVariant()); // NULL
var_dump($srCyrlInfo->getVariant()); // string(4) "Cyrl"
var_dump($zhTwInfo->getVariantName()); // NULL
var_dump($srCyrlInfo->getVariantName()); // string(8) "Cyrillic"
var_dump($zhTwInfo->getRegion()); // string(2) "TW"
var_dump($srCyrlInfo->getRegion()); // NULL
var_dump($zhTwInfo->getRegionName()); // string(6) "Taiwan"
var_dump($srCyrlInfo->getRegionName()); // NULL
var_dump($zhTwInfo->getFullIsoName()); // string(7) "Chinese"
var_dump($caInfo->getFullIsoName()); // string(18) "Catalan, Valencian"
var_dump($zhTwInfo->getFullNativeName()); // string(38) "中文 (Zhōngwén), 汉语, 漢語"
var_dump($caInfo->getFullNativeName()); // string(18) "català, valencià"
var_dump($zhTwInfo->getIsoName()); // string(7) "Chinese"
var_dump($caInfo->getIsoName()); // string(7) "Catalan"
var_dump($zhTwInfo->getNativeName()); // string(20) "中文 (Zhōngwén)"
var_dump($caInfo->getNativeName()); // string(7) "català"
var_dump($zhTwInfo->getIsoDescription()); // string(16) "Chinese (Taiwan)"
var_dump($srCyrlInfo->getIsoDescription()); // string(18) "Serbian (Cyrillic)"
var_dump($caInfo->getIsoDescription()); // string(7) "Catalan"
var_dump($zhTwInfo->getNativeDescription()); // string(29) "中文 (Zhōngwén) (Taiwan)"
var_dump($srCyrlInfo->getNativeDescription()); // string(34) "српски језик (Cyrillic)"
var_dump($caInfo->getNativeDescription()); // string(7) "català"
var_dump($zhTwInfo->getFullIsoDescription()); // string(16) "Chinese (Taiwan)"
var_dump($srCyrlInfo->getFullIsoDescription()); // string(18) "Serbian (Cyrillic)"
var_dump($caInfo->getFullIsoDescription()); // string(18) "Catalan, Valencian"
var_dump($zhTwInfo->getFullNativeDescription()); // string(47) "中文 (Zhōngwén), 汉语, 漢語 (Taiwan)"
var_dump($srCyrlInfo->getFullNativeDescription()); // string(34) "српски језик (Cyrillic)"
var_dump($caInfo->getFullNativeDescription()); // string(18) "català, valencià"

$srCyrlInfo->setIsoName('foo, bar')->setNativeName('biz, baz');
var_dump($srCyrlInfo->getIsoName()); // string(3) "foo"
var_dump($srCyrlInfo->getFullIsoName()); // string(8) "foo, bar"
var_dump($srCyrlInfo->getFullIsoDescription()); // string(19) "foo, bar (Cyrillic)"
var_dump($srCyrlInfo->getNativeName()); // string(3) "biz"
var_dump($srCyrlInfo->getFullNativeName()); // string(8) "biz, baz"
var_dump($srCyrlInfo->getFullNativeDescription()); // string(19) "biz, baz (Cyrillic)"

// You can also access directly regions/languages lists:
var_dump(\Carbon\Language::all()['zh']);
/*
array(2) {
  ["isoName"]=>
  string(7) "Chinese"
  ["nativeName"]=>
  string(38) "中文 (Zhōngwén), 汉语, 漢語"
}
*/
var_dump(\Carbon\Language::regions()['TW']); // string(6) "Taiwan"

If ever you have to change globally the locale for a particular process, you should use executeWithLocale to encapsulate this process. This way, even if an exception is thrown the global locale with be set back to its previous value.

php
Carbon::executeWithLocale('fr', function () {
	echo CarbonInterval::create(2, 1)->forHumans() . "\n";
	echo Carbon::parse('-2 hours')->diffForHumans();
});
/*
2 ans 1 mois
il y a 2 heures
*/

Symfony Translator details

The Carbon translator will use internal directory src/Carbon/Lang to find translations files in it by default but you can change/add/remove directory.

php
$translator = Translator::get('en');
$directories = $translator->getDirectories();
var_dump($directories); // Check actual directory

// Change the whole list
$translator->setDirectories([
	'corporate/translations',
	'users/translations',
]);
// Add one directory to the list
$translator->addDirectory('external/translations/directory');
// Remove one directory from the list
$translator->removeDirectory('users/translations');

// After such a settings change, you could need to clear the cache with `resetMessages`
$translator->resetMessages();

// To restore the initial settings simply recall setDirectories with the original list:
$translator->setDirectories($directories);

Then you can find all language files across those directories.

php
$translator = Translator::get();
var_dump($translator->getLocalesFiles()); // /path/to/af.php, /path/to/ar.php, etc.
var_dump($translator->getAvailableLocales()); // af, ar, etc.

// You can also filter files/locales starting with a given prefix:
echo implode(', ', array_map('basename', $translator->getLocalesFiles('fr')));
echo implode(', ', $translator->getAvailableLocales('fr'));

You can access some dynamic properties translated by calling following methods with the name of the base property.

php
$date = Carbon::parse('2018-02-25 14:00');

echo $date->locale('af_ZA')->meridiem();                 // NM
echo "\n";                                              
echo $date->locale('af_ZA')->meridiem(true);             // nm
echo "\n";                                              
// Some languages has alternative numbers available:
echo $date->locale('ja_JP')->translateNumber(45);        // 四十五
echo "\n";                                              
// You can also choose a key linked to a numeric value to translate:
echo $date->locale('ja_JP')->getAltNumber('day');        // 二十五
// Note: translations methods like translateNumber and getAltNumber are available
// on CarbonInterval and CarbonPeriod too.
echo "\n";                                              
echo $date->locale('en_SG')->ordinal('day');             // 25th
echo "\n";                                              
// As ordinal can be gender specific or have context dependency, you can pass the period format as second argument:

$date = Carbon::parse('2018-01-01 14:00');

echo $date->locale('fr_CH')->ordinal('isoWeek', 'w');    // 1re
echo "\n";                                              
echo $date->locale('fr_CH')->ordinal('day', 'd');        // 1er
echo "\n";

Finally, you can get and set messages from the internal cache:

php
$translator = Translator::get('en');

echo Carbon::now()->addSeconds(312)->setLocalTranslator($translator)->diffForHumans();    // 5 minutes from now
echo "\n";                                                                               

// Below, setMessages will load the english file(s) if available and if not yet loaded in cache, then will change the
// 'from_now' translation
$translator->setMessages('en', [
	'from_now' => 'in :time',
]);

echo Carbon::now()->addSeconds(312)->setLocalTranslator($translator)->diffForHumans();    // in 5 minutes
echo "\n";                                                                               
echo $translator->getMessages('en')['from_now'];                                          // in :time

setMessages is equivalent to setTranslations but you can omit the locale as it will use the current one, so we recommend to use it when you can as in this previous example.

Supported Locales

LocaleLanguageDiff syntax1-day diff2-days diffMonth namesWeek daysUnitsShort unitsPeriod
aaAfar
afAfrikaans
agqAghem
agrAguaruna
akAkan
amAmharic
anAragonese
anpAngika
arArabic
asAssamese
asaAsu
astAsturian
aycSouthern Aymara
azAzerbaijani
basBasaa
beBelarusian
bemBemba
berber
bezBena
bgBulgarian
bhbBhili
bhoBhojpuri
biBislama
bmBambara
bnBengali
boTibetan
brBreton
brxBodo
bsBosnian
bynBilin
caCatalan
ccpChakma
ceChechen
cggChiga
chrCherokee
ckbckb
cmnChinese
crhCrimean Turkish
csCzech
csbKashubian
cuChurch Slavic
cvChuvash
cyWelsh
daDanish
davTaita
deGerman
djeZarma
doiDogri (macrolanguage)
dsbLower Sorbian
duaDuala
dvDivehi
dyoJola-Fonyi
dzDzongkha
ebuEmbu
eeEwe
elGreek (modern)
enEnglish
eoEsperanto
esSpanish
etEstonian
euBasque
ewoEwondo
faPersian
ffFulah
fiFinnish
filFilipino
foFaroese
frFrench
furFriulian
fyWestern Frisian
gaIrish
gdGaelic
gezGeez
glGalician
gomKonkani
gswSwiss German
guGujarati
guzGusii
gvManx
haHausa
hakHakka Chinese
hawHawaiian
heHebrew (modern)
hiHindi
hifFiji Hindi
hneChhattisgarhi
hrCroatian
hsbUpper Sorbian
htHaitian
huHungarian
hyArmenian
i18ni18n
iaInterlingua
idIndonesian
igIgbo
iiSichuan Yi
ikInupiaq
inin
isIcelandic
itItalian
iuInuktitut
iwiw
jaJapanese
jgoNgomba
jmcMachame
jvJavanese
kaGeorgian
kabKabyle
kamKamba
kdeMakonde
keaKabuverdianu
khqKoyra Chiini
kiKikuyu
kkKazakh
kkjKako
klKalaallisut
klnKalenjin
kmCentral Khmer
knKannada
koKorean
kokKonkani
ksKashmiri
ksbShambala
ksfBafia
kshColognian
kuKurdish
kwCornish
kyKirghiz
lagLangi
lbLuxembourgish
lgGanda
liLimburgan
lijLigurian
lktLakota
lnLingala
loLao
lrcNorthern Luri
ltLithuanian
luLuba-Katanga
luoLuo
luyLuyia
lvLatvian
lzhLiterary Chinese
magMagahi
maiMaithili
masMasai
merMeru
mfeMorisyen
mgMalagasy
mghMakhuwa-Meetto
mgoMetaʼ
mhrEastern Mari
miMaori
miqMískito
mjwKarbi
mkMacedonian
mlMalayalam
mnMongolian
mniManipuri
momo
mrMarathi
msMalay
mtMaltese
muaMundang
myBurmese
mznMazanderani
nanMin Nan Chinese
naqNama
nbNorwegian Bokmål
ndNorth Ndebele
ndsLow German
neNepali
nhnCentral Nahuatl
niuNiuean
nlDutch
nmgKwasio
nnNorwegian Nynorsk
nnhNgiemboon
noNorwegian
nrSouth Ndebele
nsoNorthern Sotho
nusNuer
nynNyankole
ocOccitan
omOromo
orOriya
osOssetian
paPanjabi
papPapiamento
plPolish
prgPrussian
psPashto
ptPortuguese
quQuechua
quzCusco Quechua
rajRajasthani
rmRomansh
rnRundi
roRomanian
rofRombo
ruRussian
rwKinyarwanda
rwkRwa
saSanskrit
sahSakha
saqSamburu
satSantali
sbpSangu
scSardinian
sdSindhi
seNorthern Sami
sehSena
sesKoyraboro Senni
sgSango
sgsSamogitian
shsh
shiTachelhit
shnShan
shsShuswap
siSinhala
sidSidamo
skSlovak
slSlovenian
smSamoan
smnInari Sami
snShona
soSomali
sqAlbanian
srSerbian
ssSwati
stSouthern Sotho
svSwedish
swSwahili
szlSilesian
taTamil
tcyTulu
teTelugu
teoTeso
tetTetum
tgTajik
thThai
theChitwania Tharu
tiTigrinya
tigTigre
tkTurkmen
tlTagalog
tlhKlingon
tnTswana
toTongan (Tonga Islands)
tpiTok Pisin
trTurkish
tsTsonga
ttTatar
twqTasawaq
tzlTalossan
tzmTamazight
ugUighur
ukUkrainian
unmUnami
urUrdu
uzUzbek
vaiVai
veVenda
viVietnamese
voVolapük
vunVunjo
waWalloon
waeWalser
walWolaytta
woWolof
xhXhosa
xogSoga
yavYangben
yiYiddish
yoYoruba
yueCantonese
yuwYau (Morobe Province)
zghStandard Moroccan Tamazight
zhChinese
zuZulu

Please let me close this section by thanking some projects that helped us a lot to support more locales, and internationalization features:

  • jenssegers/date: many features were in this project that extends Carbon before being in Carbon itself.
  • momentjs: many features are inspired by momentjs and made to be compatible with this front-side pair project.
  • glibc was a strong base for adding and checking languages.
  • svenfuchs/rails-i18n also helped to add and check languages.
  • We used glosbe.com a lot to check translations and fill blanks.