Formatting numbers, dates/times, sizes and intervals with localization

Last updated on
28 October 2016

Drupal 7 will no longer be supported after January 5, 2025. Learn more and find resources for Drupal 7 sites

While t() can translate strings from one language to another, there are cases where we must display item counts, dates/times, etc. Drupal provides a family of functions recognizable via the format_*() naming convention. Let's examine these formatting functions.

format_plural() to format counts of things

Signature: format_plural($count, $singular, $plural, $args = array(), $langcode = NULL)

When we need to display counts of comments in an English string, for example, there are two possible formats we should use depending on whether the comment count equals one or is a higher number. The first case yields '1 comment', while the second is similar to '16 comments', for example. The difference is that the second version uses the plural form of 'comment'. Since writing the conditional expressions yourself would be troublesome, Drupal provides the format_plural() function to format strings properly when counts of things are involved. You should use it as follows:

  $comment_summary = format_plural($comment_count, '1 comment', '@count comments');

The second and third parameters to format_plural() are the singular and plural versions of the string, while the first parameter provides the @count value.

We did not use t() or any other translation function beyond format_plural() in this example. Drupal knows automatically that the second and third parameters are the strings to translate, and will translate them when required.

We could use @count in the first string as well, or just use 1, since by English language rules, it is only used when $count is one.

In reality, however, this is only true for some of the languages in the world. There are languages, like English, that have two distinct variations but different rules to select between them, and there are languages which have four or even more variations with complex rules for the selection. Because you are writing Drupal source code in English, you should be free to follow the simple rules of English here, and let translators worry about the rest.

As a matter of illustration, let's see just a few examples without striving for completeness, so you get a feel of the underlying logic:

Number of variations Example languages Notes
1 Bhutani, Persian, Hungarian, Indonesian, etc. These do not even have two variants officially, but the same form is used for all counts. Some of these language translation teams however opted to use two variants for more flawless translation.
2 English, Greek, Finnish, etc. These languages use the most widely utilized plural rules. The singular string is only used when the count is 1 and otherwise (if less or more), the plural string is used.
2 French French also uses two variants, but the rules are different. The singular string is used when the count equals or is less than 1 and otherwise (if more), the plural string is used.
3 Croatian There are several languages using three forms. For example, Croatian uses the following formula to choose the right one of the three ($n is the count): $plural_index = $n % 10==1 && n % 100 != 11 ? 0 : $n%10 >= 2 && $n %10 <= 4 && (n %100 < 10 || n % 100 >= 20) ? 1 : 2;
6 Arabic The formula to using the right string from the six different forms is ($n is the count): $plural_index = $n == 1 ? 0 : $n == 0 ? 1 : $n == 2 ? 2 : $n % 100 >= 3 && $n % 100 <= 10 ? 3 : $n % 100 >= 11 && $n % 100 <= 99 ? 4 : 5;

The good news is that this information on the plural formulas is simply illustrative. If you simply use format_plural() in the above illustrated English form, all else will be taken care of by Drupal. If a language is used where there are more or less than two forms used for counts, Drupal just looks up the right one from the translation based on the formula provided with the translation. The translators only need to specify the right formula (which they reuse for all their translations) and all the forms of the translations for the given string. Just to round out this example, the six different forms for the above format_plural() call in Arabic are: "تعليق واحد", "لا تعليقات", "تعليقان", "@count تعليقات", "@count تعليقا" and "@count تعليق". Notice that not all versions use @count. When the rules end up with one variant only being used for a specific number and that number is better looking spelled out, translators might opt to do just that.

You can also use other placeholders in the strings by passing them on in the $args parameter, just like with t().

  $type_summary = format_plural($post_count, '1 @type post', '@count @type posts', array('@type' => $type));

There is finally also an optional language parameter which allows you to request formatting of the strings in a language you specify (given that it is installed on the site and translations for the singular and plural strings as well as the right plural formula are available).

Read more about format_plural() in the API docs.

format_date() to format time and date

Signature: format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL)

The format_date() function looks for a timestamp, and every other parameter is optional. There are three types of built-in date formats available: small, medium and large (or you can use a custom specified format). format_date() uses the given language to generate short or long month names as well as day names. It does not use a language specific date format for the built-in formats, since this feature is not part of Drupal 6, but the individual components are properly translated automatically.

  // Prints the current date/time in the longest format with components in the current language.
  $now = format_date(time(), 'large');

One best practice is to reuse the small, medium and large formats instead of using your own custom date and time formats. That allows the site to set up formats more suitable for the locale at hand, and your module to follow that setup.

There is also an optional language parameter on format_date() which allows you to request a date with components translated to a given language.

Read more about format_date() in the API docs.

format_size() to format file sizes

Signature: format_size($size, $langcode = NULL)

An even simpler function is format_size() which has just two parameters: an integer with the size and an optional language specifier. As with other format functions, if the language is not given, the page's language is used. This is generally how you will use this function.

  // Formats the number $file_size as file size.
  $size = format_size($file_size);

The role of this function is to format sizes in a human-readable format, such as '567 bytes' or '5 MB'. Every part of the size is properly translated for the target language.

Read more about format_size() in the API docs.

format_interval() to format time intervals

Signature: format_interval($timestamp, $granularity = 2, $langcode = NULL)

Finally, format_interval() lets you format time intervals given as an integer counting elapsed seconds into a human-readable format such as '3 weeks 4 days' or '5 hours 43 minutes'. In the first parameter, you specify the elapsed time, the second parameter allows you to choose the granularity. There is the usual optional language parameter at the end.

  // 7.5 days * 24 hours * 60 minutes * 60 seconds, will print
  // the equivalent of "7 days 12 hours" in the given language.
  $interval = format_interval(7.5 * 24 * 60 * 60);

The components of the interval are of course localized appropriately.

Read more about format_interval() in the API docs.

Help improve this page

Page status: No known problems

You can: