[![Dart CI](https://github.com/dart-lang/i18n/actions/workflows/intl.yml/badge.svg)](https://github.com/dart-lang/i18n/actions/workflows/intl.yml)
[![Pub](https://img.shields.io/pub/v/intl.svg)](https://pub.dev/packages/intl)

Provides internationalization and localization facilities,
including message translation, plurals and genders, date/number formatting
and parsing, and bidirectional text.

## General
The most important library is [intl][intl_lib]. It defines the [Intl][Intl]
class, with the default locale and methods for accessing most of the
internationalization mechanisms. This library also defines the
[DateFormat][DateFormat], [NumberFormat][NumberFormat], and
[BidiFormatter][BidiFormatter] classes.

## Current locale

The package has a single current locale, called [defaultLocale][defaultLocale].
Operations will use that locale unless told to do otherwise.

You can explicitly set the global locale

```dart
Intl.defaultLocale = 'pt_BR';
```

or get it from the browser

```dart
import 'package:intl/intl_browser.dart';
...
findSystemLocale().then(runTheRestOfMyProgram);
```

To override the current locale for a particular operation, pass the operation
to [withLocale][withLocale]. Note that this includes async tasks
spawned from that operation, and that the argument to
[withLocale][withLocale]
will supercede the [defaultLocale][defaultLocale] while the operation
is active. If you are using different locales within an application,
the [withLocale][withLocale] operation may be preferable to setting
[defaultLocale][defaultLocale].

```dart
Intl.withLocale('fr', () => print(myLocalizedMessage()));
```

To specify the locale for an operation you can create a format object in
a specific locale, pass in the locale as a parameter to methods, or
set the default locale.

```dart
var format = DateFormat.yMd('ar');
var dateString = format.format(DateTime.now());
```

or

```dart
print(myMessage(dateString, locale: 'ar');
```

or

```dart
Intl.defaultLocale = 'es';
DateFormat.jm().format(DateTime.now());
```

## Initialization

All the different types of locale data require an async initialization step
to make
sure the data is available. This reduces the size of the application by only
loading the
data that is actually required.

Each different area of internationalization (messages, dates, numbers) requires
a separate initialization process. That way, if the application only needs to
format dates, it doesn't need to take the time or space to load up messages,
numbers, or other things it may not need.

With messages, there is also a need to import a file that won't exist until
the code generation step has been run. This can be awkward, but can be worked
around by creating a stub `messages_all.dart` file, running an empty translation
step, or commenting out the import until translations are available.
See "Extracting and Using Translated Messages"

## Messages

Messages to be localized are written as functions that return the result of
an [Intl.message][Intl.message] call.

```dart
String continueMessage() => Intl.message(
    'Hit any key to continue',
    name: 'continueMessage',
    args: [],
    desc: 'Explains that we will not proceed further until '
        'the user presses a key');
print(continueMessage());
```

This provides, in addition to the basic message string, a name, a description
for translators, the arguments used in the message, and examples. The `name` and
`args` parameters must match the name (or ClassName_methodName) and arguments
list of the function respectively. For messages without parameters, both of
these can be omitted.

A function with an Intl.message call can be run in the program before any
translation has been done, and will just return the message string. It can also
be extracted to a file and then be made to return a translated version without
modifying the original program. See "Extracting Messages" below for more
details.

The purpose of wrapping the message in a function is to allow it to
have parameters which can be used in the result. The message string is
allowed to use a restricted form of Dart string interpolation, where
only the function's parameters can be used, and only in simple
expressions. Local variables cannot be used, and neither can
expressions with curly braces. Only the message string can have
interpolation. The name, desc, args, and examples must be literals and
not contain interpolations. Only the args parameter can refer to
variables, and it should list exactly the function parameters. If you
are passing numbers or dates and you want them formatted, you must do
the formatting outside the function and pass the formatted string into
the message.

```dart
greetingMessage(name) => Intl.message(
    'Hello $name!',
    name: 'greetingMessage',
    args: [name],
    desc: 'Greet the user as they first open the application',
    examples: const {'name': 'Emily'});
print(greetingMessage('Dan'));
```

There is one special class of complex expressions allowed in the
message string, for plurals and genders.

```dart
remainingEmailsMessage(int howMany, String userName) =>
  Intl.message(
    '''${Intl.plural(howMany,
        zero: 'There are no emails left for $userName.',
        one: 'There is $howMany email left for $userName.',
        other: 'There are $howMany emails left for $userName.')}''',
  name: 'remainingEmailsMessage',
  args: [howMany, userName],
  desc: 'How many emails remain after archiving.',
  examples: const {'howMany': 42, 'userName': 'Fred'});

print(remainingEmailsMessage(1, 'Fred'));
```

However, since the typical usage for a plural or gender is for it to
be at the top-level, we can also omit the [Intl.message][Intl.message] call and
provide its parameters to the [Intl.plural][Intl.plural] call instead.

```dart
remainingEmailsMessage(int howMany, String userName) =>
  Intl.plural(
    howMany,
    zero: 'There are no emails left for $userName.',
    one: 'There is $howMany email left for $userName.',
    other: 'There are $howMany emails left for $userName.',
    name: 'remainingEmailsMessage',
    args: [howMany, userName],
    desc: 'How many emails remain after archiving.',
    examples: const {'howMany': 42, 'userName': 'Fred'});
```

Similarly, there is an [Intl.gender][Intl.gender] message, and plurals
and genders can be nested.

```dart
notOnlineMessage(String userName, String userGender) =>
  Intl.gender(
    userGender,
    male: '$userName is unavailable because he is not online.',
    female: '$userName is unavailable because she is not online.',
    other: '$userName is unavailable because they are not online',
    name: 'notOnlineMessage',
    args: [userName, userGender],
    desc: 'The user is not available to hangout.',
    examples: const {{'userGender': 'male', 'userName': 'Fred'},
        {'userGender': 'female', 'userName' : 'Alice'}});
```

It's recommended to use complete sentences in the sub-messages to keep
the structure as simple as possible for the translators.

## Extracting And Using Translated Messages

When your program contains messages that need translation, these must
be extracted from the program source, sent to human translators, and the
results need to be incorporated. The code for this is in the
[Intl_translation][Intl_translation] package.

To extract messages, run the `extract_to_arb.dart` program.

```console
> pub run intl_translation:extract_to_arb --output-dir=target/directory
    my_program.dart more_of_my_program.dart
```

This will produce a file `intl_messages.arb` with the messages from
all of these programs. See [ARB][ARB].
The resulting translations can be used to generate a set of libraries
using the `generate_from_arb.dart` program.

This expects to receive a series of files, one per
locale.

```console
> pub run intl_translation:generate_from_arb --generated_file_prefix=<prefix>
    <my_dart_files> <translated_ARB_files>
```

This will generate Dart libraries, one per locale, which contain the
translated versions. Your Dart libraries can import the primary file,
named `<prefix>messages_all.dart`, and then call the initialization
for a specific locale. Once that's done, any
[Intl.message][Intl.message] calls made in the context of that locale
will automatically print the translated version instead of the
original.

```dart
import 'my_prefix_messages_all.dart';
...
initializeMessages('dk').then(printSomeMessages);
```

Once the future returned from the initialization call returns, the
message data is available.

## Number Formatting and Parsing

To format a number, create a NumberFormat instance.

```dart
var f = NumberFormat('###.0#', 'en_US');
print(f.format(12.345));
  ==> 12.35
```

The locale parameter is optional. If omitted, then it will use the
current locale. The format string is as described in
[NumberFormat][NumberFormat]

It's also possible to access the number symbol data for the current
locale, which provides information as to the various separator
characters, patterns, and other information used for formatting, as

```dart
f.symbols
```

Current known limitations are that the currency format will only print
the name of the currency, and does not support currency symbols, and
that the scientific format does not really agree with scientific
notation. Number parsing is not yet implemented.

## Date Formatting and Parsing

To format a [DateTime][DateTime], create a [DateFormat][DateFormat]
instance. These can be created using a set of commonly used skeletons
taken from ICU/CLDR or using an explicit pattern. For details on the
supported skeletons and patterns see [DateFormat][DateFormat].

```dart
DateFormat.yMMMMEEEEd().format(aDateTime);
  ==> 'Wednesday, January 10, 2012'
DateFormat('EEEEE', 'en_US').format(aDateTime);
  ==> 'Wednesday'
DateFormat('EEEEE', 'ln').format(aDateTime);
  ==> 'mokɔlɔ mwa mísáto'
```

You can also parse dates using the same skeletons or patterns.

```dart
DateFormat.yMd('en_US').parse('1/10/2012');
DateFormat('Hms', 'en_US').parse('14:23:01');
```

Skeletons can be combined, the main use being to print a full date and
time, e.g.

```dart
DateFormat.yMEd().add_jms().format(DateTime.now());
  ==> 'Thu, 5/23/2013 10:21:47 AM'
```

Known limitations: Time zones are not yet supported. Dart
[DateTime][DateTime] objects don't have a time zone, so are either
local or UTC. Formatting and parsing Durations is not yet implemented.

Note that before doing any DateTime formatting for a particular
locale, you must load the appropriate data by calling.

```dart
import 'package:intl/date_symbol_data_local.dart';
...
initializeDateFormatting('de_DE', null).then(formatDates);
```

Once the future returned from the initialization call returns, the
formatting data is available.

There are other mechanisms for loading the date formatting data
implemented, but we expect to deprecate those in favor of having the
data in a library as in the above, and using deferred loading to only
load the portions that are needed. For the time being, this will
include all of the data, which will increase code size.

## Bidirectional Text

The class [BidiFormatter][BidiFormatter] provides utilities for
working with Bidirectional text. We can wrap the string with unicode
directional indicator characters or with an HTML span to indicate
direction. The direction can be specified with the
[RTL][BidiFormatter.RTL] and [LTR][BidiFormatter.LTR] constructors, or
detected from the text.

```dart
BidiFormatter.RTL().wrapWithUnicode('xyz');
BidiFormatter.RTL().wrapWithSpan('xyz');
```

[intl_lib]: https://pub.dev/documentation/intl/latest/intl/intl-library.html
[Intl]: https://pub.dev/documentation/intl/latest/intl/Intl-class.html
[DateFormat]: https://pub.dev/documentation/intl/latest/intl/DateFormat-class.html
[NumberFormat]: https://pub.dev/documentation/intl/latest/intl/NumberFormat-class.html
[withLocale]: https://pub.dev/documentation/intl/latest/intl/Intl/withLocale.html
[defaultLocale]: https://pub.dev/documentation/intl/latest/intl/Intl/defaultLocale.html
[Intl.message]: https://pub.dev/documentation/intl/latest/intl/Intl/message.html
[Intl_translation]: https://pub.dev/packages/intl_translation
[Intl.plural]: https://pub.dev/documentation/intl/latest/intl/Intl/plural.html
[Intl.gender]: https://pub.dev/documentation/intl/latest/intl/Intl/gender.html
[DateTime]: https://api.dart.dev/dart-core/DateTime-class.html
[BidiFormatter]: https://pub.dev/documentation/intl/latest/intl/BidiFormatter-class.html
[BidiFormatter.RTL]: https://pub.dev/documentation/intl/latest/intl/BidiFormatter/BidiFormatter.RTL.html
[BidiFormatter.LTR]: https://pub.dev/documentation/intl/latest/intl/BidiFormatter/BidiFormatter.LTR.html
[ARB]: https://github.com/google/app-resource-bundle
