Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling DateTime, Currency and Numbers in gen_l10n tool #47008

Closed
shihaohong opened this issue Dec 13, 2019 · 6 comments
Closed

Handling DateTime, Currency and Numbers in gen_l10n tool #47008

shihaohong opened this issue Dec 13, 2019 · 6 comments
Assignees
Labels
a: internationalization Supporting other languages or locales. (aka i18n) c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter

Comments

@shihaohong
Copy link
Contributor

shihaohong commented Dec 13, 2019

It would be great to provide some support/convenience for handling DateTime, numbers and currencies in the gen_l10n tool. I've been working with @HansMuller on some of ideas:

DateTime handling

Pull requests:

Simple, non-plural messages - #47006
Plural messages - #47483

Description

Essentially handles DateTime through reading the "type" and "format" resource attributes for each placeholder. By defining the "type" as "DateTime" and providing a "format" string that corresponds to an existing DateFormat constructor, the tool will automatically generate code that formats the date or time for the developer.

It generates the following result:
Message in .arb file:

{
  "springBegins": "Spring begins on {springStartDate}",
  "@springBegins": {
    "description": "The first day of spring",
    "placeholders": {
      "springStartDate": {
        "type": "DateTime",
        "format": "yMMMMEEEEd"
      }
    }
  }
}

Resulting method:

  String springBegins(Object springStartDate) {
    final DateFormat springStartDateDateFormat = DateFormat.yMMMMEEEEd(_localeName);
    final String springStartDateString = springStartDateDateFormat.format(springStartDate);
    return Intl.message(
      r'Spring begins on \$springStartDateString',
      locale: _localeName,
      name: 'springBegins',
      desc: r'The first day of spring',
      args: <Object>[springStartDateString]
    );
  }

This takes away complexity from the app developer from having to format dates for each locale themselves.

Currency

Pull requests

Fix positional vs named params, introduce Currency formatting - #48445

Description

Essentially handles currencies through intl.NumberFormat through reading the "type, "format", and optional attributes such as "decimalDigits" for resource attributes for each placeholder. The tool will automatically generate code that formats the date or time for the developer.

Message in .arb file:

{
  "itemCostMessage": "Your item is {cost} dollars.",
  "@itemCostMessage": {
    "description": "The monetary cost of a single item.",
    "placeholders": {
      "cost": {
        "type": "Number",
        "format": "simpleCurrency",
        "decimalDigits": 2
      }
    }
  }
}

Resulting method:

  String itemCostMessage(Object cost) {
    final NumberFormat costNumberFormat = NumberFormat.simpleCurrency({
      locale: _locale,
      decimalDigits: 2,
    });
    final String costString = costNumberFormat.format(cost);

    return Intl.message(
      r'Your item is \$costString dollars.',
      locale: _localeName,
      name: 'itemCostMessage',
      desc: r'The monetary cost of a single item.',
      args: <Object>[cost]
    );
  }

Numbers

Pull requests

Handles number formats for simple and plural messages - #47706

Description

Essentially handles numbers through intl.NumberFormat through reading the "type, "format", and optional attributes such as "decimalDigits" for resource attributes for each placeholder. The tool will automatically generate code that formats the date or time for the developer.

Message in .arb file:

{
  "courseCompletion": "You have completed {progress} of the course.",
  "@courseCompletion": {
    "description": "The amount of progress the student has made in their class.",
    "placeholders": {
      "progress": {
        "type": "Number",
        "format": "percentPattern",
      }
    }
  }
}

Resulting method:

  String courseCompletion(Object progress) {
    final NumberFormat progressNumberFormat = NumberFormat.percentPattern({
      locale: _locale,
    });
    final String progressString = progressNumberFormat.format(progress);

    return Intl.message(
      r'You have completed \$progress of the course.',
      locale: _localeName,
      name: 'courseCompletion',
      desc: r'The amount of progress the student has made in their class.',
      args: <Object>[progress]
    );
  }
@shihaohong
Copy link
Contributor Author

shihaohong commented Jan 8, 2020

I updated the original proposal to have currencies be specified with the type "Number", since currencies are also formatted using the NumberFormat class. I don't see any added benefit of separating "Number" and "Currency" types since they are processed the same way under the hood, but if there are any objections, please comment on the thread!

@shihaohong
Copy link
Contributor Author

I believe that this issue can be closed, since all functionality in this proposal has been merged.

@garry-jeromson
Copy link

garry-jeromson commented Jan 16, 2020

Sanity check: is this most excellent functionality ready for use?

Running the tool from the current master branch and looking at the generated messages_xx.dart files, there are a couple of issues with DateTime placeholders:

  • The only mapping functions (m1, m2, etc.) present are those for placeholders with type string - for DateTime types, there are no mapping functions
  • Strings with placeholders of type DateTime are missing in the keys in the_notInlinedMessages function.

This means that the fallback message (see #48822) is always shown.

An example would be:

messages_en.arb:

{
"responseDueBy": "The response is due by {time} on {day}.",
	"@responseDueBy": {
		"description": "Response due time",
		"placeholders": {
			"time": {
				"description": "Time that the response is due",
				"type": "DateTime",
				"format": "Hm"
			},
			"day": {
				"description": "Day that the response is due",
				"type": "DateTime",
				"format": "yMMMMEEEEd"
			}
		}
	}
}

messages_de.arb:

{
"responseDueBy": "Die Antwort wird bis {time} am {day} erstellt.",
}

The generated content in both messages_xx.dartfiles is:

...

class MessageLookup extends MessageLookupByLibrary {
  String get localeName => 'en';

  final messages = _notInlinedMessages(_notInlinedMessages);
  static _notInlinedMessages(_) => <String, Function>{};
}

@HansMuller
Copy link
Contributor

@garry-jeromson - could you open a new issue and include a test case that demonstrates how the generated localizations class fails?

@garry-jeromson
Copy link

@HansMuller Will do. :-)

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 24, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: internationalization Supporting other languages or locales. (aka i18n) c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter
Projects
None yet
Development

No branches or pull requests

3 participants