translations_test.dart 12.1 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'dart:convert';
6 7
import 'dart:io';

8
import 'package:flutter/cupertino.dart';
9
import 'package:flutter/services.dart';
10 11
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
12
import 'package:path/path.dart' as path;
13

14 15
import '../test_utils.dart';

16
final String rootDirectoryPath = Directory.current.path;
17

18
void main() {
19
  for (final String language in kCupertinoSupportedLanguages) {
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
    testWidgets('translations exist for $language', (WidgetTester tester) async {
      final Locale locale = Locale(language);

      expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue);

      final CupertinoLocalizations localizations = await GlobalCupertinoLocalizations.delegate.load(locale);

      expect(localizations.datePickerYear(0), isNotNull);
      expect(localizations.datePickerYear(1), isNotNull);
      expect(localizations.datePickerYear(2), isNotNull);
      expect(localizations.datePickerYear(10), isNotNull);

      expect(localizations.datePickerMonth(1), isNotNull);
      expect(localizations.datePickerMonth(2), isNotNull);
      expect(localizations.datePickerMonth(11), isNotNull);
      expect(localizations.datePickerMonth(12), isNotNull);

37 38 39 40 41
      expect(localizations.datePickerStandaloneMonth(1), isNotNull);
      expect(localizations.datePickerStandaloneMonth(2), isNotNull);
      expect(localizations.datePickerStandaloneMonth(11), isNotNull);
      expect(localizations.datePickerStandaloneMonth(12), isNotNull);

42 43 44 45 46
      expect(localizations.datePickerDayOfMonth(0), isNotNull);
      expect(localizations.datePickerDayOfMonth(1), isNotNull);
      expect(localizations.datePickerDayOfMonth(2), isNotNull);
      expect(localizations.datePickerDayOfMonth(10), isNotNull);

47 48 49 50 51
      expect(localizations.datePickerDayOfMonth(0, 1), isNotNull);
      expect(localizations.datePickerDayOfMonth(1, 2), isNotNull);
      expect(localizations.datePickerDayOfMonth(2, 3), isNotNull);
      expect(localizations.datePickerDayOfMonth(10, 4), isNotNull);

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
      expect(localizations.datePickerMediumDate(DateTime(2019, 3, 25)), isNotNull);

      expect(localizations.datePickerHour(0), isNotNull);
      expect(localizations.datePickerHour(1), isNotNull);
      expect(localizations.datePickerHour(2), isNotNull);
      expect(localizations.datePickerHour(10), isNotNull);

      expect(localizations.datePickerHourSemanticsLabel(0), isNotNull);
      expect(localizations.datePickerHourSemanticsLabel(1), isNotNull);
      expect(localizations.datePickerHourSemanticsLabel(2), isNotNull);
      expect(localizations.datePickerHourSemanticsLabel(10), isNotNull);
      expect(localizations.datePickerHourSemanticsLabel(0), isNot(contains(r'$hour')));
      expect(localizations.datePickerHourSemanticsLabel(1), isNot(contains(r'$hour')));
      expect(localizations.datePickerHourSemanticsLabel(2), isNot(contains(r'$hour')));
      expect(localizations.datePickerHourSemanticsLabel(10), isNot(contains(r'$hour')));

      expect(localizations.datePickerDateOrder, isNotNull);
      expect(localizations.datePickerDateTimeOrder, isNotNull);
      expect(localizations.anteMeridiemAbbreviation, isNotNull);
      expect(localizations.postMeridiemAbbreviation, isNotNull);
      expect(localizations.alertDialogLabel, isNotNull);

      expect(localizations.timerPickerHour(0), isNotNull);
      expect(localizations.timerPickerHour(1), isNotNull);
      expect(localizations.timerPickerHour(2), isNotNull);
      expect(localizations.timerPickerHour(10), isNotNull);

      expect(localizations.timerPickerMinute(0), isNotNull);
      expect(localizations.timerPickerMinute(1), isNotNull);
      expect(localizations.timerPickerMinute(2), isNotNull);
      expect(localizations.timerPickerMinute(10), isNotNull);

      expect(localizations.timerPickerSecond(0), isNotNull);
      expect(localizations.timerPickerSecond(1), isNotNull);
      expect(localizations.timerPickerSecond(2), isNotNull);
      expect(localizations.timerPickerSecond(10), isNotNull);

      expect(localizations.timerPickerHourLabel(0), isNotNull);
      expect(localizations.timerPickerHourLabel(1), isNotNull);
      expect(localizations.timerPickerHourLabel(2), isNotNull);
      expect(localizations.timerPickerHourLabel(10), isNotNull);

      expect(localizations.timerPickerMinuteLabel(0), isNotNull);
      expect(localizations.timerPickerMinuteLabel(1), isNotNull);
      expect(localizations.timerPickerMinuteLabel(2), isNotNull);
      expect(localizations.timerPickerMinuteLabel(10), isNotNull);

      expect(localizations.timerPickerSecondLabel(0), isNotNull);
      expect(localizations.timerPickerSecondLabel(1), isNotNull);
      expect(localizations.timerPickerSecondLabel(2), isNotNull);
      expect(localizations.timerPickerSecondLabel(10), isNotNull);

      expect(localizations.cutButtonLabel, isNotNull);
      expect(localizations.copyButtonLabel, isNotNull);
      expect(localizations.pasteButtonLabel, isNotNull);
      expect(localizations.selectAllButtonLabel, isNotNull);
108 109 110 111 112 113

      expect(localizations.tabSemanticsLabel(tabIndex: 2, tabCount: 5), isNotNull);
      expect(localizations.tabSemanticsLabel(tabIndex: 2, tabCount: 5), isNot(contains(r'$tabIndex')));
      expect(localizations.tabSemanticsLabel(tabIndex: 2, tabCount: 5), isNot(contains(r'$tabCount')));
      expect(() => localizations.tabSemanticsLabel(tabIndex: 0, tabCount: 5), throwsAssertionError);
      expect(() => localizations.tabSemanticsLabel(tabIndex: 2, tabCount: 0), throwsAssertionError);
114 115 116 117
    });
  }

  testWidgets('Spot check French', (WidgetTester tester) async {
118
    const Locale locale = Locale('fr');
119 120
    expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue);
    final CupertinoLocalizations localizations = await GlobalCupertinoLocalizations.delegate.load(locale);
Dan Field's avatar
Dan Field committed
121
    expect(localizations, isA<CupertinoLocalizationFr>());
122
    expect(localizations.alertDialogLabel, 'Alerte');
123 124
    expect(localizations.datePickerHourSemanticsLabel(1), '1 heure');
    expect(localizations.datePickerHourSemanticsLabel(12), '12 heures');
125 126 127 128 129 130
    expect(localizations.pasteButtonLabel, 'Coller');
    expect(localizations.datePickerDateOrder, DatePickerDateOrder.dmy);
    expect(localizations.timerPickerSecondLabel(20), 's');
    expect(localizations.selectAllButtonLabel, 'Tout sélect.');
    expect(localizations.timerPickerMinute(10), '10');
  });
131 132 133 134 135

  testWidgets('Spot check Chinese', (WidgetTester tester) async {
    const Locale locale = Locale('zh');
    expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue);
    final CupertinoLocalizations localizations = await GlobalCupertinoLocalizations.delegate.load(locale);
Dan Field's avatar
Dan Field committed
136
    expect(localizations, isA<CupertinoLocalizationZh>());
137 138 139 140 141 142 143 144 145
    expect(localizations.alertDialogLabel, '提醒');
    expect(localizations.datePickerHourSemanticsLabel(1), '1 点');
    expect(localizations.datePickerHourSemanticsLabel(12), '12 点');
    expect(localizations.pasteButtonLabel, '粘贴');
    expect(localizations.datePickerDateOrder, DatePickerDateOrder.ymd);
    expect(localizations.timerPickerSecondLabel(20), '秒');
    expect(localizations.selectAllButtonLabel, '全选');
    expect(localizations.timerPickerMinute(10), '10');
  });
146 147 148

  // Regression test for https://github.com/flutter/flutter/issues/53036.
  testWidgets('`nb` uses `no` as its synonym when `nb` arb file is not present', (WidgetTester tester) async {
149 150 151 152 153 154 155
    final File nbCupertinoArbFile = File(
      path.join(rootDirectoryPath, 'lib', 'src', 'l10n', 'cupertino_nb.arb'),
    );
    final File noCupertinoArbFile = File(
      path.join(rootDirectoryPath, 'lib', 'src', 'l10n', 'cupertino_no.arb'),
    );

156 157

    if (noCupertinoArbFile.existsSync() && !nbCupertinoArbFile.existsSync()) {
158
      Locale locale = const Locale.fromSubtags(languageCode: 'no');
159 160 161 162 163 164 165 166
      expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue);
      CupertinoLocalizations localizations = await GlobalCupertinoLocalizations.delegate.load(locale);
      expect(localizations, isA<CupertinoLocalizationNo>());

      final String pasteButtonLabelNo = localizations.pasteButtonLabel;
      final String copyButtonLabelNo = localizations.copyButtonLabel;
      final String cutButtonLabelNo = localizations.cutButtonLabel;

167
      locale = const Locale.fromSubtags(languageCode: 'nb');
168 169 170 171 172 173 174 175
      expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue);
      localizations = await GlobalCupertinoLocalizations.delegate.load(locale);
      expect(localizations, isA<CupertinoLocalizationNb>());
      expect(localizations.pasteButtonLabel, pasteButtonLabelNo);
      expect(localizations.copyButtonLabel, copyButtonLabelNo);
      expect(localizations.cutButtonLabel, cutButtonLabelNo);
    }
  });
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

  // Regression test for https://github.com/flutter/flutter/issues/36704.
  testWidgets('kn arb file should be properly Unicode escaped', (WidgetTester tester) async {
    final File file = File(
      path.join(rootDirectoryPath, 'lib', 'src', 'l10n', 'cupertino_kn.arb'),
    );

    final Map<String, dynamic> bundle = json.decode(file.readAsStringSync()) as Map<String, dynamic>;

    // Encodes the arb resource values if they have not already been
    // encoded.
    encodeBundleTranslations(bundle);

    // Generates the encoded arb output file in as a string.
    final String encodedArbFile = generateArbString(bundle);

    // After encoding the bundles, the generated string should match
    // the existing material_kn.arb.
    if (Platform.isWindows) {
      // On Windows, the character '\n' can output the two-character sequence
      // '\r\n' (and when reading the file back, '\r\n' is translated back
      // into a single '\n' character).
      expect(file.readAsStringSync().replaceAll('\r\n', '\n'), encodedArbFile);
    } else {
      expect(file.readAsStringSync(), encodedArbFile);
    }
  });
203 204 205 206 207 208 209 210 211

  // Regression test for https://github.com/flutter/flutter/issues/110451.
  testWidgets('Finnish translation for tab label', (WidgetTester tester) async {
    const Locale locale = Locale('fi');
    expect(GlobalCupertinoLocalizations.delegate.isSupported(locale), isTrue);
    final CupertinoLocalizations localizations = await GlobalCupertinoLocalizations.delegate.load(locale);
    expect(localizations, isA<CupertinoLocalizationFi>());
    expect(localizations.tabSemanticsLabel(tabIndex: 1, tabCount: 2), 'Välilehti 1 kautta 2');
  });
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264

  // Regression test for https://github.com/flutter/flutter/issues/130874.
  testWidgets('buildButtonItems builds a localized "No Replacements found" button when no suggestions', (WidgetTester tester) async {
    await tester.pumpWidget(
      CupertinoApp(
        locale: const Locale('ru'),
        localizationsDelegates: GlobalCupertinoLocalizations.delegates,
        supportedLocales: const <Locale>[Locale('en'), Locale('ru')],
        home: _FakeEditableText()
      ),
    );
    final _FakeEditableTextState editableTextState =
        tester.state(find.byType(_FakeEditableText));
    final List<ContextMenuButtonItem>? buttonItems =
        CupertinoSpellCheckSuggestionsToolbar.buildButtonItems(editableTextState);

    expect(buttonItems, isNotNull);
    expect(buttonItems, hasLength(1));
    expect(buttonItems!.first.label, 'Варианты замены не найдены');
    expect(buttonItems.first.onPressed, isNull);
  });

}

class _FakeEditableText extends EditableText {
  _FakeEditableText() : super(
    controller: TextEditingController(),
    focusNode: FocusNode(),
    backgroundCursorColor: CupertinoColors.white,
    cursorColor: CupertinoColors.white,
    style: const TextStyle(),
  );

  @override
  _FakeEditableTextState createState() => _FakeEditableTextState();
}

class _FakeEditableTextState extends EditableTextState {
  _FakeEditableTextState();

  @override
  TextEditingValue get currentTextEditingValue => TextEditingValue.empty;

  @override
  SuggestionSpan? findSuggestionSpanAtCursorIndex(int cursorIndex) {
    return const SuggestionSpan(
      TextRange(
        start: 0,
        end: 0,
      ),
      <String>[],
    );
  }
265
}