Unverified Commit 1cfba262 authored by Andrey Suvorov's avatar Andrey Suvorov Committed by GitHub

fixes l10n for CupertinoDatePicker in monthYear mode (#130934)

This PR fixes l10n issue when months names are being used in incorrect form in CupertinoDatePicker in CupertinoDatePickerMode.yearMonth (#130930).

The idea of this proposal is to add an optional parameter `standalone` for `CupertinoLocalizations.datePickerMonth` to be able to choose when to use months names in base form (intl DateSymbols.STANDALONEMONTHS) and when in day-dependent form (intl DateSymbols.MONTHS)

<details>
<summary>Before</summary>

<img width="366" alt="image" src="https://github.com/flutter/flutter/assets/32621121/1dd54fa7-6dd9-4053-889b-57134c145432">

<img width="387" alt="image" src="https://github.com/flutter/flutter/assets/32621121/c176070e-73e4-49d3-883b-ba31eca6d1d7">

</details>

<details>
<summary>After</summary>

<img width="369" alt="image" src="https://github.com/flutter/flutter/assets/32621121/255594f1-219d-4bd4-9b75-1012912f8ab0">

<img width="378" alt="image" src="https://github.com/flutter/flutter/assets/32621121/16bbb41f-3f62-4446-bf41-e27140b649a9">

</details>
parent 5a556f8e
......@@ -438,8 +438,9 @@ class CupertinoDatePicker extends StatefulWidget {
_PickerColumnType columnType,
CupertinoLocalizations localizations,
BuildContext context,
bool showDayOfWeek
) {
bool showDayOfWeek, {
bool standaloneMonth = false,
}) {
String longestText = '';
switch (columnType) {
......@@ -491,8 +492,10 @@ class CupertinoDatePicker extends StatefulWidget {
}
}
case _PickerColumnType.month:
for (int i = 1; i <=12; i++) {
final String month = localizations.datePickerMonth(i);
for (int i = 1; i <= 12; i++) {
final String month = standaloneMonth
? localizations.datePickerStandaloneMonth(i)
: localizations.datePickerMonth(i);
if (longestText.length < month.length) {
longestText = month;
}
......@@ -1280,11 +1283,12 @@ class _CupertinoDatePickerDateState extends State<CupertinoDatePicker> {
final int month = index + 1;
final bool isInvalidMonth = (widget.minimumDate?.year == selectedYear && widget.minimumDate!.month > month)
|| (widget.maximumDate?.year == selectedYear && widget.maximumDate!.month < month);
final String monthName = (widget.mode == CupertinoDatePickerMode.monthYear) ? localizations.datePickerStandaloneMonth(month) : localizations.datePickerMonth(month);
return itemPositioningBuilder(
context,
Text(
localizations.datePickerMonth(month),
monthName,
style: _themeTextStyle(context, isValid: !isInvalidMonth),
),
);
......@@ -1577,7 +1581,8 @@ class _CupertinoDatePickerMonthYearState extends State<CupertinoDatePicker> {
}
void _refreshEstimatedColumnWidths() {
estimatedColumnWidths[_PickerColumnType.month.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.month, localizations, context, false);
estimatedColumnWidths[_PickerColumnType.month.index] =
CupertinoDatePicker._getColumnWidth(_PickerColumnType.month, localizations, context, false, standaloneMonth: widget.mode == CupertinoDatePickerMode.monthYear);
estimatedColumnWidths[_PickerColumnType.year.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.year, localizations, context, false);
}
......@@ -1613,11 +1618,12 @@ class _CupertinoDatePickerMonthYearState extends State<CupertinoDatePicker> {
final int month = index + 1;
final bool isInvalidMonth = (widget.minimumDate?.year == selectedYear && widget.minimumDate!.month > month)
|| (widget.maximumDate?.year == selectedYear && widget.maximumDate!.month < month);
final String monthName = (widget.mode == CupertinoDatePickerMode.monthYear) ? localizations.datePickerStandaloneMonth(month) : localizations.datePickerMonth(month);
return itemPositioningBuilder(
context,
Text(
localizations.datePickerMonth(month),
monthName,
style: _themeTextStyle(context, isValid: !isInvalidMonth),
),
);
......
......@@ -76,9 +76,25 @@ abstract class CupertinoLocalizations {
///
/// - US English: January
/// - Korean: 1월
/// - Russian: января
// The global version uses date symbols data from the intl package.
String datePickerMonth(int monthIndex);
/// Month that is shown in [CupertinoDatePicker] spinner corresponding to
/// the given month index in [CupertinoDatePickerMode.monthYear] mode.
///
/// This is distinct from [datePickerMonth] because in some languages, like Russian,
/// the name of a month takes a different form depending
/// on whether it is preceded by a day or whether it stands alone.
///
/// Examples: datePickerMonth(1) in:
///
/// - US English: January
/// - Korean: 1월
/// - Russian: Январь
// The global version uses date symbols data from the intl package.
String datePickerStandaloneMonth(int monthIndex);
/// Day of month that is shown in [CupertinoDatePicker] spinner corresponding
/// to the given day index.
///
......@@ -367,6 +383,9 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations {
@override
String datePickerMonth(int monthIndex) => _months[monthIndex - 1];
@override
String datePickerStandaloneMonth(int monthIndex) => _months[monthIndex - 1];
@override
String datePickerDayOfMonth(int dayIndex, [int? weekDay]) {
if (weekDay != null) {
......
......@@ -100,6 +100,18 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
return _fullYearFormat.dateSymbols.MONTHS[monthIndex - 1];
}
@override
String datePickerStandaloneMonth(int monthIndex) {
// It doesn't actually have anything to do with _fullYearFormat. It's just
// taking advantage of the fact that _fullYearFormat loaded the needed
// locale's symbols.
//
// Because this will be used without specifying any day of month,
// in most cases it should be capitalized (according to rules in specific language).
return intl.toBeginningOfSentenceCase(_fullYearFormat.dateSymbols.STANDALONEMONTHS[monthIndex - 1]) ??
_fullYearFormat.dateSymbols.STANDALONEMONTHS[monthIndex - 1];
}
@override
String datePickerDayOfMonth(int dayIndex, [int? weekDay]) {
if (weekDay != null) {
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/cupertino.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Test correct month form for CupertinoDatePicker in monthYear mode', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: CupertinoPageScaffold(
child: Center(
child: CupertinoDatePicker(
initialDateTime: DateTime(2023, 5),
onDateTimeChanged: (_) {},
mode: CupertinoDatePickerMode.monthYear,
)),
),
supportedLocales: const <Locale>[Locale('ru', 'RU')],
localizationsDelegates: GlobalCupertinoLocalizations.delegates,
),
);
expect(find.text('Май'), findsWidgets);
});
testWidgets('Test correct month form for CupertinoDatePicker in date mode', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: CupertinoPageScaffold(
child: Center(
child: CupertinoDatePicker(
initialDateTime: DateTime(2023, 5),
onDateTimeChanged: (_) {},
mode: CupertinoDatePickerMode.date,
)),
),
supportedLocales: const <Locale>[Locale('ru', 'RU')],
localizationsDelegates: GlobalCupertinoLocalizations.delegates,
),
);
expect(find.text('мая'), findsWidgets);
});
}
......@@ -34,6 +34,11 @@ void main() {
expect(localizations.datePickerMonth(11), isNotNull);
expect(localizations.datePickerMonth(12), isNotNull);
expect(localizations.datePickerStandaloneMonth(1), isNotNull);
expect(localizations.datePickerStandaloneMonth(2), isNotNull);
expect(localizations.datePickerStandaloneMonth(11), isNotNull);
expect(localizations.datePickerStandaloneMonth(12), isNotNull);
expect(localizations.datePickerDayOfMonth(0), isNotNull);
expect(localizations.datePickerDayOfMonth(1), isNotNull);
expect(localizations.datePickerDayOfMonth(2), isNotNull);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment