From 9eb1a95916230ddc4d39b2b60ad0794d17533105 Mon Sep 17 00:00:00 2001 From: ultraelectronica Date: Sun, 18 Oct 2026 10:17:13 +0800 Subject: [PATCH 1/4] Add Noto Sans Tagalog font fallback and locale resolution - Register NotoSansTagalog in the theme font fallback list alongside NotoSansSC for the Baybayin pilot - Use kAppLocalizationsDelegates and resolveAppLocale for locale handling in the app widget --- lib/app/app.dart | 3 ++- lib/core/theme/app_theme.dart | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/app/app.dart b/lib/app/app.dart index c7813145..16a5c3bd 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -79,8 +79,9 @@ class FlickPlayerApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: AppTheme.darkTheme, navigatorKey: rootNavigatorKey, - localizationsDelegates: AppLocalizations.localizationsDelegates, + localizationsDelegates: kAppLocalizationsDelegates, supportedLocales: kSupportedLocales, + localeResolutionCallback: resolveAppLocale, // null means "follow the device locale". locale: selectedLocale, home: const _RootRouter(), diff --git a/lib/core/theme/app_theme.dart b/lib/core/theme/app_theme.dart index 5a08775b..08420778 100644 --- a/lib/core/theme/app_theme.dart +++ b/lib/core/theme/app_theme.dart @@ -14,8 +14,11 @@ class AppTheme { /// Google Sans Flex has no CJK glyphs, so Chinese comes from the bundled /// Noto Sans SC subset (see pubspec.yaml). Skia does not search bundled fonts /// for missing characters, so the fallback has to be declared explicitly - /// here. - static const List fontFamilyFallback = ['NotoSansSC']; + /// here. The same applies to the Baybayin pilot's Noto Sans Tagalog. + static const List fontFamilyFallback = [ + 'NotoSansSC', + 'NotoSansTagalog', + ]; /// Primary text theme using Google Sans Flex static TextTheme get _textTheme { From 41154444e6c8ba6a96cc4e530dd308ef607aaf3a Mon Sep 17 00:00:00 2001 From: ultraelectronica Date: Sun, 18 Oct 2026 10:17:53 +0800 Subject: [PATCH 2/4] Extract language settings into reusable LanguageSettingsCard Also add Noto Sans Tagalog license to the app info screen. --- .../screens/app_info_settings_screen.dart | 4 ++ .../screens/interface_settings_screen.dart | 42 +------------------ 2 files changed, 6 insertions(+), 40 deletions(-) diff --git a/lib/features/settings/screens/app_info_settings_screen.dart b/lib/features/settings/screens/app_info_settings_screen.dart index 48ad481f..c7ed3d3a 100644 --- a/lib/features/settings/screens/app_info_settings_screen.dart +++ b/lib/features/settings/screens/app_info_settings_screen.dart @@ -547,6 +547,10 @@ class _AppInfoSettingsScreenState extends ConsumerState ['Noto Sans SC'], await rootBundle.loadString('assets/fonts/NotoSansSC-OFL.txt'), ); + yield LicenseEntryWithLineBreaks( + ['Noto Sans Tagalog'], + await rootBundle.loadString('assets/fonts/NotoSansTagalog-OFL.txt'), + ); }); } Navigator.of(context).push( diff --git a/lib/features/settings/screens/interface_settings_screen.dart b/lib/features/settings/screens/interface_settings_screen.dart index bcfa5a56..feed7526 100644 --- a/lib/features/settings/screens/interface_settings_screen.dart +++ b/lib/features/settings/screens/interface_settings_screen.dart @@ -7,6 +7,7 @@ import 'package:flick/core/utils/app_haptics.dart'; import 'package:flick/providers/providers.dart'; import 'package:flick/services/milestone_service.dart'; import 'package:flick/features/settings/widgets/settings_widgets.dart'; +import 'package:flick/features/settings/widgets/language_settings_card.dart'; import 'package:flick/features/settings/screens/bottom_bar_settings_screen.dart'; import 'package:flick/features/settings/screens/visualizer_settings_screen.dart'; import 'package:flick/l10n/l10n.dart'; @@ -38,46 +39,7 @@ class InterfaceSettingsScreen extends ConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ SettingsSectionHeader(context.l10n.language), - SettingsCard( - children: [ - ValueListenableBuilder( - valueListenable: LocaleController.instance, - builder: (context, selectedLocale, _) { - return Column( - children: [ - SelectionSetting( - icon: LucideIcons.smartphone, - title: context.l10n.languageSystemDefault, - subtitle: context.l10n.languageSectionDescription, - selected: selectedLocale == null, - onTap: () => LocaleController.instance.select(null), - ), - const SettingsDivider(), - SelectionSetting( - icon: LucideIcons.languages, - title: '简体中文', - subtitle: l10n.simplifiedChinese, - selected: selectedLocale?.languageCode == 'zh', - onTap: () => LocaleController.instance.select( - const Locale('zh', 'CN'), - ), - ), - const SettingsDivider(), - SelectionSetting( - icon: LucideIcons.globe, - title: l10n.english, - subtitle: l10n.english, - selected: selectedLocale?.languageCode == 'en', - onTap: () => LocaleController.instance.select( - const Locale('en'), - ), - ), - ], - ); - }, - ), - ], - ), + const LanguageSettingsCard(), const SizedBox(height: AppConstants.spacingLg), SettingsSectionHeader(l10n.interfaceLabel), SettingsCard( From 0b05b25b95025cdd261b1c015dc052dbd075f362 Mon Sep 17 00:00:00 2001 From: ultraelectronica Date: Sun, 18 Oct 2026 10:17:59 +0800 Subject: [PATCH 3/4] Add opt-in Baybayin locale with partial pilot strings Introduce the tl-Tglg locale as a script-specific opt-in: script matching keeps ordinary tl devices from selecting it, and stored locale tags are parsed script-aware. The pilot inherits English ICU rules so untranslated messages pluralize correctly while Localizations still reports the Tagalog-in-Baybayin locale. --- lib/l10n/app_en.arb | 4 + lib/l10n/app_zh.arb | 4 + lib/l10n/generated/app_localizations.dart | 25 ++++- lib/l10n/generated/app_localizations_en.dart | 4 + lib/l10n/generated/app_localizations_zh.dart | 3 + lib/l10n/l10n.dart | 99 +++++++++++++++++--- 6 files changed, 123 insertions(+), 16 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index a807bfc1..86233ca1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1098,6 +1098,10 @@ } } }, + "baybayinPilotDescription": "Experimental draft; untranslated text stays in English.", + "@baybayinPilotDescription": { + "description": "Language selector warning for the partial, opt-in Tagalog-in-Baybayin pilot." + }, "beLsbBigEndianSubslotLsb": "BE-LSB — big-endian subslot, LSB first", "@beLsbBigEndianSubslotLsb": { "description": "lib/features/settings/screens/uac2_preferences_screen.dart:1722" diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index d884b1b0..ec5551f8 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -227,6 +227,10 @@ "bassMidTreble": "低音、中音与高音", "bassTreble": "低频 + 高频", "battery": "电量 {battery}%", + "baybayinPilotDescription": "实验性草稿;未翻译的内容仍显示英文。", + "@baybayinPilotDescription": { + "description": "Language selector warning for the partial, opt-in Tagalog-in-Baybayin pilot." + }, "beLsbBigEndianSubslotLsb": "BE-LSB — 大端子槽,LSB 在前", "beMsbBigEndianSubslotMsb": "BE-MSB —— 大端子槽,MSB 优先(默认)", "beMsbPackingTheDefaultWire": "BE-MSB 打包 — 默认传输约定", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 3ee7c2b0..414ce915 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -6,6 +6,7 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:intl/intl.dart' as intl; import 'app_localizations_en.dart'; +import 'app_localizations_tl.dart'; import 'app_localizations_zh.dart'; // ignore_for_file: type=lint @@ -95,6 +96,8 @@ abstract class AppLocalizations { /// A list of this localizations delegate's supported locales. static const List supportedLocales = [ Locale('en'), + Locale('tl'), + Locale.fromSubtags(languageCode: 'tl', scriptCode: 'Tglg'), Locale('zh'), ]; @@ -1466,6 +1469,12 @@ abstract class AppLocalizations { /// **'{battery}% battery'** String battery(Object battery); + /// Language selector warning for the partial, opt-in Tagalog-in-Baybayin pilot. + /// + /// In en, this message translates to: + /// **'Experimental draft; untranslated text stays in English.'** + String get baybayinPilotDescription; + /// lib/features/settings/screens/uac2_preferences_screen.dart:1722 /// /// In en, this message translates to: @@ -13487,17 +13496,31 @@ class _AppLocalizationsDelegate @override bool isSupported(Locale locale) => - ['en', 'zh'].contains(locale.languageCode); + ['en', 'tl', 'zh'].contains(locale.languageCode); @override bool shouldReload(_AppLocalizationsDelegate old) => false; } AppLocalizations lookupAppLocalizations(Locale locale) { + // Lookup logic when language+script codes are specified. + switch (locale.languageCode) { + case 'tl': + { + switch (locale.scriptCode) { + case 'Tglg': + return AppLocalizationsTlTglg(); + } + break; + } + } + // Lookup logic when only language code is specified. switch (locale.languageCode) { case 'en': return AppLocalizationsEn(); + case 'tl': + return AppLocalizationsTl(); case 'zh': return AppLocalizationsZh(); } diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 7df3d58d..ae80cbfe 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -810,6 +810,10 @@ class AppLocalizationsEn extends AppLocalizations { return '$battery% battery'; } + @override + String get baybayinPilotDescription => + 'Experimental draft; untranslated text stays in English.'; + @override String get beLsbBigEndianSubslotLsb => 'BE-LSB — big-endian subslot, LSB first'; diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 15d92745..70323b18 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -767,6 +767,9 @@ class AppLocalizationsZh extends AppLocalizations { return '电量 $battery%'; } + @override + String get baybayinPilotDescription => '实验性草稿;未翻译的内容仍显示英文。'; + @override String get beLsbBigEndianSubslotLsb => 'BE-LSB — 大端子槽,LSB 在前'; diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 685bb57c..3c641544 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -13,9 +13,11 @@ // MaterialApp.builder on every build, and once from main() before the first // frame so that strings produced during startup already use the right locale. +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flick/l10n/generated/app_localizations.dart'; +import 'package:flick/l10n/generated/app_localizations_tl.dart'; import 'package:flick/services/app_preferences_service.dart'; export 'package:flick/l10n/generated/app_localizations.dart'; @@ -27,7 +29,13 @@ export 'package:flick/l10n/generated/app_localizations.dart'; // 调用方只要 import 本文件就能拿到,无需额外 import。 export 'package:flick/l10n/model_labels.dart'; -/// Locales the app ships translations for. +/// The opt-in Tagalog-in-Baybayin pilot. `Tglg` is a script, not a language. +const Locale kBaybayinLocale = Locale.fromSubtags( + languageCode: 'tl', + scriptCode: 'Tglg', +); + +/// Locales the app ships translations for (including the partial pilot). /// /// English is listed first so that a device locale we do not translate falls /// back to English rather than to Chinese. Chinese devices still resolve to @@ -35,11 +43,50 @@ export 'package:flick/l10n/model_labels.dart'; const List kSupportedLocales = [ Locale('en'), Locale('zh', 'CN'), + kBaybayinLocale, ]; /// Used when nothing else matches. const Locale kFallbackLocale = Locale('en'); +/// Override only the pilot; keep Flutter's stock delegates for everything else. +/// The first supported delegate of each type wins. +const List> kAppLocalizationsDelegates = [ + _BaybayinLocalizationsDelegate(), + ...AppLocalizations.localizationsDelegates, +]; + +/// The partial pilot needs English ICU rules for its inherited English text. +/// Otherwise, Tagalog rules make e.g. an untranslated `songUnit(0)` say "song". +/// `localeName` here is the formatting locale; Localizations.localeOf(context) +/// still returns tl_Tglg and Flutter's built-in controls still use Tagalog. +AppLocalizations lookupFlickLocalizations(Locale requested) { + final locale = resolveSupportedLocale(requested); + return locale == kBaybayinLocale + ? _BaybayinWithEnglishFallback() + : lookupAppLocalizations(locale); +} + +class _BaybayinWithEnglishFallback extends AppLocalizationsTlTglg { + @override + String get localeName => 'en'; +} + +class _BaybayinLocalizationsDelegate + extends LocalizationsDelegate { + const _BaybayinLocalizationsDelegate(); + + @override + bool isSupported(Locale locale) => locale == kBaybayinLocale; + + @override + Future load(Locale locale) => + SynchronousFuture(lookupFlickLocalizations(locale)); + + @override + bool shouldReload(_BaybayinLocalizationsDelegate old) => false; +} + /// The current localizations. Initialized to English so that reads before the /// first frame cannot throw. AppLocalizations _current = lookupAppLocalizations(kFallbackLocale); @@ -55,13 +102,32 @@ extension AppLocalizationsX on BuildContext { /// Maps [requested] onto the closest locale we actually support. Locale resolveSupportedLocale(Locale requested) { for (final supported in kSupportedLocales) { - if (supported.languageCode == requested.languageCode) { + if (supported == requested) return supported; + } + // A script-specific translation must never be selected by language alone. + // In particular, an ordinary tl/tl_PH device must not opt into Baybayin. + if (requested.scriptCode != null) { + for (final supported in kSupportedLocales) { + if (supported.languageCode == requested.languageCode && + supported.scriptCode == requested.scriptCode) { + return supported; + } + } + } + for (final supported in kSupportedLocales) { + if (supported.languageCode == requested.languageCode && + supported.scriptCode == null) { return supported; } } return kFallbackLocale; } +/// MaterialApp must use the same script-aware resolution as startup/services. +/// Flutter's default language-only fallback could otherwise select the pilot. +Locale resolveAppLocale(Locale? requested, Iterable _) => + resolveSupportedLocale(requested ?? kFallbackLocale); + /// Holds the user's language choice and keeps the global [l10n] in sync. /// /// A `null` [value] means "follow the device locale". @@ -87,6 +153,7 @@ class LocaleController extends ValueNotifier { /// Selects [locale], or `null` to follow the device locale. Future select(Locale? locale) async { + locale = locale == null ? null : resolveSupportedLocale(locale); if (locale == value) return; value = locale; await AppPreferencesService().setAppLocale(_storedFromLocale(locale)); @@ -100,7 +167,7 @@ class LocaleController extends ValueNotifier { /// Points the global accessor at [locale] without a BuildContext. Used during /// startup, before any Localizations widget exists. void bindLocale(Locale locale) { - _current = lookupAppLocalizations(resolveSupportedLocale(locale)); + _current = lookupFlickLocalizations(locale); } Locale _deviceLocale() { @@ -112,20 +179,22 @@ class LocaleController extends ValueNotifier { Locale? _localeFromStored(String? stored) { if (stored == null || stored.isEmpty || stored == systemValue) return null; - final parts = stored.split('_'); - final language = parts.first; - if (language.isEmpty) return null; - final country = parts.length > 1 && parts[1].isNotEmpty ? parts[1] : null; + // Accept both the existing en/zh_CN values and script-aware locale tags. + final match = RegExp( + r'^([A-Za-z]{2,3})(?:[_-]([A-Za-z]{4}))?(?:[_-]([A-Za-z]{2}|[0-9]{3}))?$', + ).firstMatch(stored); + if (match == null) return kFallbackLocale; + final script = match.group(2); return resolveSupportedLocale( - country == null ? Locale(language) : Locale(language, country), + Locale.fromSubtags( + languageCode: match.group(1)!.toLowerCase(), + scriptCode: script == null + ? null + : '${script[0].toUpperCase()}${script.substring(1).toLowerCase()}', + countryCode: match.group(3)?.toUpperCase(), + ), ); } - String _storedFromLocale(Locale? locale) { - if (locale == null) return systemValue; - final country = locale.countryCode; - return country == null || country.isEmpty - ? locale.languageCode - : '${locale.languageCode}_$country'; - } + String _storedFromLocale(Locale? locale) => locale?.toString() ?? systemValue; } From 0c5bc3ffc7cf905169fb1fdabe8bca20e45bd63a Mon Sep 17 00:00:00 2001 From: ultraelectronica Date: Sun, 18 Oct 2026 10:18:12 +0800 Subject: [PATCH 4/4] Add experimental Baybayin locale pilot Bundle Noto Sans Tagalog, add a 50-message tl_Tglg draft with Latin transliterations, and wire a language option with review docs and tests. --- assets/fonts/NotoSansTagalog-OFL.txt | 93 + assets/fonts/NotoSansTagalog-Regular.ttf | Bin 0 -> 53012 bytes docs/BAYBAYIN_REVIEW.md | 167 + .../widgets/language_settings_card.dart | 55 + lib/l10n/app_tl.arb | 4 + lib/l10n/app_tl_Tglg.arb | 304 + lib/l10n/generated/app_localizations_tl.dart | 8138 +++++++++++++++++ pubspec.yaml | 9 + test/l10n/baybayin_layout_test.dart | 246 + test/l10n/baybayin_pilot_test.dart | 174 + test/l10n/locale_switch_test.dart | 147 +- 11 files changed, 9335 insertions(+), 2 deletions(-) create mode 100644 assets/fonts/NotoSansTagalog-OFL.txt create mode 100644 assets/fonts/NotoSansTagalog-Regular.ttf create mode 100644 docs/BAYBAYIN_REVIEW.md create mode 100644 lib/features/settings/widgets/language_settings_card.dart create mode 100644 lib/l10n/app_tl.arb create mode 100644 lib/l10n/app_tl_Tglg.arb create mode 100644 lib/l10n/generated/app_localizations_tl.dart create mode 100644 test/l10n/baybayin_layout_test.dart create mode 100644 test/l10n/baybayin_pilot_test.dart diff --git a/assets/fonts/NotoSansTagalog-OFL.txt b/assets/fonts/NotoSansTagalog-OFL.txt new file mode 100644 index 00000000..65a12930 --- /dev/null +++ b/assets/fonts/NotoSansTagalog-OFL.txt @@ -0,0 +1,93 @@ +Copyright 2022 The Noto Project Authors (https://github.com/notofonts/tagalog) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software, provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the Font Software. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/assets/fonts/NotoSansTagalog-Regular.ttf b/assets/fonts/NotoSansTagalog-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ca69d2626661d2baf304e591bad6914574314aef GIT binary patch literal 53012 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 literal 0 HcmV?d00001 diff --git a/docs/BAYBAYIN_REVIEW.md b/docs/BAYBAYIN_REVIEW.md new file mode 100644 index 00000000..812e7251 --- /dev/null +++ b/docs/BAYBAYIN_REVIEW.md @@ -0,0 +1,167 @@ +# Baybayin pilot review + +**Experimental draft: these translations are not linguistically verified.** +The app offers Tagalog written in Baybayin (`tl_Tglg`), not a language named +“Baybayin.” This first pass translates 50 messages, not the entire interface. +Everything else deliberately stays in English. + +## Try it + +Run `flutter run --flavor full` on Android, then open +**Settings → Interface → Language → Tagalog (Baybayin)**. The option's subtitle +warns that this is a partial draft. Language names stay recognizable, and +**English** is always written in Latin script so you can switch back. +Ordinary `tl`, `tl_PH`, `tl_Latn`, and `fil` device locales do not select Baybayin. + +## Review conventions first + +- This draft uses modern final-consonant spelling with **U+1714 TAGALOG SIGN + VIRAMA** (᜔). It does not silently omit final consonants or mix in U+1715 + pamudpod (᜕). The bundled font covers both for subsequent review decisions. +- **Da/ra share ᜇ**; e/i share ᜒ and o/u share ᜓ. The draft does not use the + separate modern ra glyph. Please decide whether to keep these conventions. +- `mga` is written ᜋᜅ; standalone `ng` is spelled for its pronunciation *nang*, + ᜈᜅ᜔. Hyphens and ordinary punctuation are retained. +- Reviewer corrections use **kanta** for songs, **kumanta** for artist labels, + and **Lirika** for Lyrics. Related singular/plural labels and song counts use + these terms consistently. Next song uses **Susunod na kanta**, while Previous + song uses **Nakaraang kanta** (including the mini-player customization label). + These Latin wording corrections do not yet approve the Baybayin spellings. +- Please scrutinize **polder**, **Mga pagsasaayos**, and **Ihalo** as UI terms. + These are proposed choices, not an established glossary. + Loanword adaptation, pronunciation and brevity all need your judgment. +- Numbers, ICU placeholders and technical/product names are not transliterated. + Song titles, artist/album names, paths, user-created playlist names and actual + lyrics are not converted. “Album,” “Artist,” etc. below are interface labels. +- `songsCount` intentionally uses the same counted noun in both ICU branches; + please review the rendered results for 0, 1, 2 and 101. + +## How to approve or correct a row + +1. Judge the **Latin Tagalog wording** against the English meaning and context. +2. Read the **Baybayin independently** and check that it says the intended + Tagalog, including every vowel/final mark. Mechanical transcription is not + proof of correctness. +3. Try the actual action in the app. In particular, distinguish pause/stop, + remove/delete, and play-next/add-to-queue. +4. Edit `lib/l10n/app_tl_Tglg.arb`: update the message, its `x-latin`, and its + `x-review-status` (`draft`, `needs-change`, or `approved`). Only the human + reviewer should mark a row approved. Keep the corresponding row below in + sync; automated tests check the table against the ARB, including context. +5. Run `flutter gen-l10n`, `flutter test test/l10n`, and `flutter analyze`. + +All rows start as **draft**. Passing tests establishes technical integrity, not +linguistic approval. Do not call the locale verified or remove the experimental +warning until the human review and the device checklist are complete. + +## Review sheet + +| Key | English | Context | Latin Tagalog draft | Baybayin draft | Status | +| --- | --- | --- | --- | --- | --- | +| `addToQueue` | Add to Queue | Song action: append to the playback queue. | Idagdag sa pila | ᜁᜇᜄ᜔ᜇᜄ᜔ ᜐ ᜉᜒᜎ | draft | +| `album` | Album | Playback source label, not an album's name. | Album | ᜀᜎ᜔ᜊᜓᜋ᜔ | draft | +| `albums` | Albums | Album navigation tab and screen title. | Mga album | ᜋᜅ ᜀᜎ᜔ᜊᜓᜋ᜔ | draft | +| `allSongs` | All Songs | Playback source for the entire song library. | Lahat ng kanta | ᜎᜑᜆ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ | draft | +| `artist` | Artist | Playback source label, not a performer's name. Review the term for musical artists. | Kumanta | ᜃᜓᜋᜈ᜔ᜆ | draft | +| `artists` | Artists | Artist navigation tab and screen title. Review the term for musical artists. | Mga kumanta | ᜋᜅ ᜃᜓᜋᜈ᜔ᜆ | draft | +| `back` | Back | Return to the previous step or page. | Bumalik | ᜊᜓᜋᜎᜒᜃ᜔ | draft | +| `cancel` | Cancel | Cancel a dialog or action without applying it. | Kanselahin | ᜃᜈ᜔ᜐᜒᜎᜑᜒᜈ᜔ | draft | +| `close` | Close | Dismiss the current surface. | Isara | ᜁᜐᜇ | draft | +| `delete` | Delete | Destructive delete action. Check against the separate Remove action. | Burahin | ᜊᜓᜇᜑᜒᜈ᜔ | draft | +| `deselectAll` | Deselect all | Clear the selection, not the songs themselves. | Alisin lahat ng pinili | ᜀᜎᜒᜐᜒᜈ᜔ ᜎᜑᜆ᜔ ᜈᜅ᜔ ᜉᜒᜈᜒᜎᜒ | draft | +| `done` | Done | Finish the current task. | Tapos | ᜆᜉᜓᜐ᜔ | draft | +| `favorites` | Favorites | Favorites navigation tab, screen title and player action. | Mga paborito | ᜋᜅ ᜉᜊᜓᜇᜒᜆᜓ | draft | +| `folder` | Folder | Playback source label, not a directory name. Draft adapts folder to polder. | Polder | ᜉᜓᜎ᜔ᜇᜒᜇ᜔ | draft | +| `folders` | Folders | Folder navigation tab and screen title. Review the adapted loanword. | Mga polder | ᜋᜅ ᜉᜓᜎ᜔ᜇᜒᜇ᜔ | draft | +| `interfaceLabel` | Interface | Interface settings page title; contains the language selector. | Itsura | ᜁᜆ᜔ᜐᜓᜇ | draft | +| `language` | Language | Language section heading in interface settings. | Wika | ᜏᜒᜃ | draft | +| `languageSectionDescription` | Choose the language used across the app. | Language selector helper text. Review length at enlarged text sizes. | Piliin ang wikang gagamitin sa aplikasyon. | ᜉᜒᜎᜒᜁᜈ᜔ ᜀᜅ᜔ ᜏᜒᜃᜅ᜔ ᜄᜄᜋᜒᜆᜒᜈ᜔ ᜐ ᜀᜉ᜔ᜎᜒᜃᜐ᜔ᜌᜓᜈ᜔. | draft | +| `languageSystemDefault` | System default | Follow the device's language rather than an explicit app language. | Wika ng aparato | ᜏᜒᜃ ᜈᜅ᜔ ᜀᜉᜇᜆᜓ | draft | +| `lyrics` | Lyrics | Lyrics action label only; never transliterate the lyrics themselves. | Lirika | ᜎᜒᜇᜒᜃ | draft | +| `menu` | Menu | Menu navigation tab. | Talaan | ᜆᜎᜀᜈ᜔ | draft | +| `next` | Next | Advance to the next onboarding or tutorial step, not a song. | Susunod | ᜐᜓᜐᜓᜈᜓᜇ᜔ | draft | +| `nextSong` | Next song | Next-song playback control tooltip. | Susunod na kanta | ᜐᜓᜐᜓᜈᜓᜇ᜔ ᜈ ᜃᜈ᜔ᜆ | draft | +| `noSongsFound` | No Songs Found | Empty song list message. | Walang nahanap na kanta | ᜏᜎᜅ᜔ ᜈᜑᜈᜉ᜔ ᜈ ᜃᜈ᜔ᜆ | draft | +| `nowPlaying` | Now Playing | Now-playing screen heading. | Kasalukuyang tumutugtog | ᜃᜐᜎᜓᜃᜓᜌᜅ᜔ ᜆᜓᜋᜓᜆᜓᜄ᜔ᜆᜓᜄ᜔ | draft | +| `off` | Off | Disabled/off mode label, including shuffle and repeat. | Patay | ᜉᜆᜌ᜔ | draft | +| `pause` | Pause | Temporarily pause playback; distinct from Stop. | Ihinto muna | ᜁᜑᜒᜈ᜔ᜆᜓ ᜋᜓᜈ | draft | +| `play` | Play | Start or resume playback. | Patugtugin | ᜉᜆᜓᜄ᜔ᜆᜓᜄᜒᜈ᜔ | draft | +| `playNext` | Play next | Song action: insert immediately after the current song. | Isunod | ᜁᜐᜓᜈᜓᜇ᜔ | draft | +| `playlist2` | Playlist | Playback source label, not a user-created playlist name. | Talaan ng kanta | ᜆᜎᜀᜈ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ | draft | +| `playlists` | Playlists | Playlist navigation tab and screen title. | Mga talaan ng kanta | ᜋᜅ ᜆᜎᜀᜈ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ | draft | +| `previousSong` | Previous song | Previous-song playback control tooltip. | Nakaraang kanta | ᜈᜃᜇᜀᜅ᜔ ᜃᜈ᜔ᜆ | draft | +| `previousSong2` | Previous Song | Previous-song label in mini-player customization; match the playback control. | Nakaraang kanta | ᜈᜃᜇᜀᜅ᜔ ᜃᜈ᜔ᜆ | draft | +| `queue` | Queue | Playback queue title and player action label. | Pila | ᜉᜒᜎ | draft | +| `remove` | Remove | Remove from a queue/list; distinct from deleting a file. | Alisin | ᜀᜎᜒᜐᜒᜈ᜔ | draft | +| `repeat` | Repeat: {arg1} | Repeat-mode feedback. arg1 is the already-localized mode label. | Ulit: {arg1} | ᜂᜎᜒᜆ᜔: {arg1} | draft | +| `repeatMode` | Repeat Mode | Repeat-mode picker title. | Paraan ng pag-ulit | ᜉᜇᜀᜈ᜔ ᜈᜅ᜔ ᜉᜄ᜔-ᜂᜎᜒᜆ᜔ | draft | +| `search` | Search | Search navigation tab and action. | Hanapin | ᜑᜈᜉᜒᜈ᜔ | draft | +| `selectAll` | Select All | Select every item without modifying its metadata. | Piliin lahat | ᜉᜒᜎᜒᜁᜈ᜔ ᜎᜑᜆ᜔ | draft | +| `settings` | Settings | Settings navigation tab and screen title. Review this terminology. | Mga pagsasaayos | ᜋᜅ ᜉᜄ᜔ᜐᜐᜀᜌᜓᜐ᜔ | draft | +| `share` | Share | Share action. | Ibahagi | ᜁᜊᜑᜄᜒ | draft | +| `shuffle` | Shuffle | Shuffle-play action. | Ihalo | ᜁᜑᜎᜓ | draft | +| `shuffle2` | Shuffle: {arg1} | Shuffle-mode feedback. arg1 is the already-localized mode label. | Paghalo: {arg1} | ᜉᜄ᜔ᜑᜎᜓ: {arg1} | draft | +| `shuffleMode` | Shuffle Mode | Shuffle-mode picker title. | Paraan ng paghalo | ᜉᜇᜀᜈ᜔ ᜈᜅ᜔ ᜉᜄ᜔ᜑᜎᜓ | draft | +| `songs` | {arg1} • {arg2} songs | Album detail subtitle: arg1 is duration, arg2 is song count. Do not change either placeholder. | {arg1} • {arg2} kanta | {arg1} • {arg2} ᜃᜈ᜔ᜆ | draft | +| `songs14` | Songs | Songs navigation tab and screen title. | Mga kanta | ᜋᜅ ᜃᜈ᜔ᜆ | draft | +| `songsCount` | {count, plural, =1{{count} song} other{{count} songs}} | Recap song count. Tagalog counted nouns do not take English's plural suffix; both ICU branches intentionally use kanta. | {count, plural, =1{{count} kanta} other{{count} kanta}} | {count, plural, =1{{count} ᜃᜈ᜔ᜆ} other{{count} ᜃᜈ᜔ᜆ}} | draft | +| `stop` | Stop | Stop an operation, such as library scanning; distinct from Pause. | Ihinto | ᜁᜑᜒᜈ᜔ᜆᜓ | draft | +| `tracks` | {_totalTracks} tracks | Album track count. Keep the underscore-prefixed placeholder unchanged. | {_totalTracks} kanta | {_totalTracks} ᜃᜈ᜔ᜆ | draft | +| `volume` | Volume | Playback volume label and player action. | Lakas ng tunog | ᜎᜃᜐ᜔ ᜈᜅ᜔ ᜆᜓᜈᜓᜄ᜔ | draft | + +## Rendering and device checklist + +The host tests load the actual bundled fonts and exercise the selector, +navigation and mini-player at narrow widths and enlarged text sizes. Optional +review images (not pixel-golden assertions): + +```sh +flutter test test/l10n/baybayin_layout_test.dart --dart-define=BAYBAYIN_SCREENSHOTS=true +``` + +Images go to `build/baybayin_shots/`. If your Markdown reader shows boxes in +the table, use those images or the Android app; a document viewer does not +automatically load the app's bundled font. + +Still check manually on **Android 8/API 26 and a current Android version**: + +- [ ] English → Baybayin → Chinese → English updates the visible UI. +- [ ] Force-stop/relaunch retains Baybayin, and choosing System default restores + device-following behavior. Filipino/Tagalog system settings stay in English + unless the user explicitly chooses the Baybayin script. +- [ ] Kudlit and virama sit correctly, including in bold; no boxes, detached + marks or clipped ascenders/descenders. Review both short and long labels. +- [ ] At the largest system font size, scroll the language card and activate the + always-Latin **English** option. Also check nav labels and player tooltips. +- [ ] Actual song/artist/album/playlist names and lyrics remain unchanged. +- [ ] Flutter's built-in dialogs/date pickers/text-selection controls load + successfully. **Their stock Tagalog labels are Latin-script Tagalog, not + Baybayin**; they are outside this 50-message pilot. +- [ ] Android notifications, lock screen and home widgets: verify separately. + Native resource translations were not added, native views do not inherit + the Flutter font, and service-created app labels may follow the app locale. + Do not infer native rendering support from the Flutter tests. +- [ ] TalkBack: check focus, announcements and language switching. Baybayin + pronunciation is **not guaranteed** by installed Tagalog TTS. Use English + if the screen reader cannot read this experimental script reliably. + +## Implementation notes + +- `app_tl.arb` is intentionally empty, required by Flutter's script-variant + generator. It is not offered as a separate app language; the generated base + supplies English fallback messages. Do not fill it with copied English text. +- `kSupportedLocales` and `resolveAppLocale` control the actual app options; + the generated list additionally includes the internal `tl` base. +- Use `kAppLocalizationsDelegates` and `lookupFlickLocalizations` for the app, + not the raw generated lookup/delegate. The pilot deliberately uses English + ICU formatting rules (`localeName == 'en'`) for both inherited and translated + app messages, so untranslated plurals retain English grammar. The UI locale + remains `tl_Tglg`; Flutter's stock controls still resolve Tagalog normally. + Revisit the per-message formatting policy before expanding beyond the pilot. +- The full, unmodified **Noto Sans Tagalog Regular** adds 53,012 bytes, is bundled + offline, declared as a theme fallback, and credited in the app's Licenses page. + No app dependency or audio-engine change is needed. +- Font source: [Google Fonts, ofl/notosanstagalog](https://github.com/google/fonts/tree/main/ofl/notosanstagalog), + Git blob `ca69d2626661d2baf304e591bad6914574314aef`. + SHA-256: `871a66319d10d1a027eee889f75ea49be0b7d2a4e97acd6bf7f7a0ed1d741aac`. + The matching SIL OFL 1.1 notice is `assets/fonts/NotoSansTagalog-OFL.txt`. diff --git a/lib/features/settings/widgets/language_settings_card.dart b/lib/features/settings/widgets/language_settings_card.dart new file mode 100644 index 00000000..7b0299aa --- /dev/null +++ b/lib/features/settings/widgets/language_settings_card.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:lucide_icons_flutter/lucide_icons.dart'; + +import 'package:flick/features/settings/widgets/settings_widgets.dart'; +import 'package:flick/l10n/l10n.dart'; + +/// Language choices keep their autonyms readable even in the draft pilot. +class LanguageSettingsCard extends StatelessWidget { + const LanguageSettingsCard({super.key}); + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder( + valueListenable: LocaleController.instance, + builder: (context, selectedLocale, _) { + return SettingsCard( + children: [ + SelectionSetting( + icon: LucideIcons.smartphone, + title: context.l10n.languageSystemDefault, + subtitle: context.l10n.languageSectionDescription, + selected: selectedLocale == null, + onTap: () => LocaleController.instance.select(null), + ), + const SettingsDivider(), + SelectionSetting( + icon: LucideIcons.languages, + title: '简体中文', + subtitle: context.l10n.simplifiedChinese, + selected: selectedLocale?.languageCode == 'zh', + onTap: () => + LocaleController.instance.select(const Locale('zh', 'CN')), + ), + const SettingsDivider(), + SelectionSetting( + icon: LucideIcons.globe, + title: 'English', + subtitle: context.l10n.english, + selected: selectedLocale?.languageCode == 'en', + onTap: () => LocaleController.instance.select(const Locale('en')), + ), + const SettingsDivider(), + SelectionSetting( + icon: LucideIcons.languages, + title: 'Tagalog (Baybayin)', + subtitle: context.l10n.baybayinPilotDescription, + selected: selectedLocale == kBaybayinLocale, + onTap: () => LocaleController.instance.select(kBaybayinLocale), + ), + ], + ); + }, + ); + } +} diff --git a/lib/l10n/app_tl.arb b/lib/l10n/app_tl.arb new file mode 100644 index 00000000..0c48b8a3 --- /dev/null +++ b/lib/l10n/app_tl.arb @@ -0,0 +1,4 @@ +{ + "@@locale": "tl", + "@@comment": "Generator-only base for tl_Tglg. Intentionally empty: all missing pilot messages inherit the English template. Plain tl is not offered by the app." +} diff --git a/lib/l10n/app_tl_Tglg.arb b/lib/l10n/app_tl_Tglg.arb new file mode 100644 index 00000000..1f3e6cda --- /dev/null +++ b/lib/l10n/app_tl_Tglg.arb @@ -0,0 +1,304 @@ +{ + "@@locale": "tl_Tglg", + "@@comment": "Experimental draft, not linguistically verified. Modern virama U+1714; shared da/ra; shared e/i and o/u. Review x-latin alongside the Baybayin. Missing messages deliberately fall back to English through the empty tl base.", + "addToQueue": "ᜁᜇᜄ᜔ᜇᜄ᜔ ᜐ ᜉᜒᜎ", + "@addToQueue": { + "description": "Song action: append to the playback queue.", + "x-latin": "Idagdag sa pila", + "x-review-status": "draft" + }, + "album": "ᜀᜎ᜔ᜊᜓᜋ᜔", + "@album": { + "description": "Playback source label, not an album's name.", + "x-latin": "Album", + "x-review-status": "draft" + }, + "albums": "ᜋᜅ ᜀᜎ᜔ᜊᜓᜋ᜔", + "@albums": { + "description": "Album navigation tab and screen title.", + "x-latin": "Mga album", + "x-review-status": "draft" + }, + "allSongs": "ᜎᜑᜆ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ", + "@allSongs": { + "description": "Playback source for the entire song library.", + "x-latin": "Lahat ng kanta", + "x-review-status": "draft" + }, + "artist": "ᜃᜓᜋᜈ᜔ᜆ", + "@artist": { + "description": "Playback source label, not a performer's name. Review the term for musical artists.", + "x-latin": "Kumanta", + "x-review-status": "draft" + }, + "artists": "ᜋᜅ ᜃᜓᜋᜈ᜔ᜆ", + "@artists": { + "description": "Artist navigation tab and screen title. Review the term for musical artists.", + "x-latin": "Mga kumanta", + "x-review-status": "draft" + }, + "back": "ᜊᜓᜋᜎᜒᜃ᜔", + "@back": { + "description": "Return to the previous step or page.", + "x-latin": "Bumalik", + "x-review-status": "draft" + }, + "cancel": "ᜃᜈ᜔ᜐᜒᜎᜑᜒᜈ᜔", + "@cancel": { + "description": "Cancel a dialog or action without applying it.", + "x-latin": "Kanselahin", + "x-review-status": "draft" + }, + "close": "ᜁᜐᜇ", + "@close": { + "description": "Dismiss the current surface.", + "x-latin": "Isara", + "x-review-status": "draft" + }, + "delete": "ᜊᜓᜇᜑᜒᜈ᜔", + "@delete": { + "description": "Destructive delete action. Check against the separate Remove action.", + "x-latin": "Burahin", + "x-review-status": "draft" + }, + "deselectAll": "ᜀᜎᜒᜐᜒᜈ᜔ ᜎᜑᜆ᜔ ᜈᜅ᜔ ᜉᜒᜈᜒᜎᜒ", + "@deselectAll": { + "description": "Clear the selection, not the songs themselves.", + "x-latin": "Alisin lahat ng pinili", + "x-review-status": "draft" + }, + "done": "ᜆᜉᜓᜐ᜔", + "@done": { + "description": "Finish the current task.", + "x-latin": "Tapos", + "x-review-status": "draft" + }, + "favorites": "ᜋᜅ ᜉᜊᜓᜇᜒᜆᜓ", + "@favorites": { + "description": "Favorites navigation tab, screen title and player action.", + "x-latin": "Mga paborito", + "x-review-status": "draft" + }, + "folder": "ᜉᜓᜎ᜔ᜇᜒᜇ᜔", + "@folder": { + "description": "Playback source label, not a directory name. Draft adapts folder to polder.", + "x-latin": "Polder", + "x-review-status": "draft" + }, + "folders": "ᜋᜅ ᜉᜓᜎ᜔ᜇᜒᜇ᜔", + "@folders": { + "description": "Folder navigation tab and screen title. Review the adapted loanword.", + "x-latin": "Mga polder", + "x-review-status": "draft" + }, + "interfaceLabel": "ᜁᜆ᜔ᜐᜓᜇ", + "@interfaceLabel": { + "description": "Interface settings page title; contains the language selector.", + "x-latin": "Itsura", + "x-review-status": "draft" + }, + "language": "ᜏᜒᜃ", + "@language": { + "description": "Language section heading in interface settings.", + "x-latin": "Wika", + "x-review-status": "draft" + }, + "languageSectionDescription": "ᜉᜒᜎᜒᜁᜈ᜔ ᜀᜅ᜔ ᜏᜒᜃᜅ᜔ ᜄᜄᜋᜒᜆᜒᜈ᜔ ᜐ ᜀᜉ᜔ᜎᜒᜃᜐ᜔ᜌᜓᜈ᜔.", + "@languageSectionDescription": { + "description": "Language selector helper text. Review length at enlarged text sizes.", + "x-latin": "Piliin ang wikang gagamitin sa aplikasyon.", + "x-review-status": "draft" + }, + "languageSystemDefault": "ᜏᜒᜃ ᜈᜅ᜔ ᜀᜉᜇᜆᜓ", + "@languageSystemDefault": { + "description": "Follow the device's language rather than an explicit app language.", + "x-latin": "Wika ng aparato", + "x-review-status": "draft" + }, + "lyrics": "ᜎᜒᜇᜒᜃ", + "@lyrics": { + "description": "Lyrics action label only; never transliterate the lyrics themselves.", + "x-latin": "Lirika", + "x-review-status": "draft" + }, + "menu": "ᜆᜎᜀᜈ᜔", + "@menu": { + "description": "Menu navigation tab.", + "x-latin": "Talaan", + "x-review-status": "draft" + }, + "next": "ᜐᜓᜐᜓᜈᜓᜇ᜔", + "@next": { + "description": "Advance to the next onboarding or tutorial step, not a song.", + "x-latin": "Susunod", + "x-review-status": "draft" + }, + "nextSong": "ᜐᜓᜐᜓᜈᜓᜇ᜔ ᜈ ᜃᜈ᜔ᜆ", + "@nextSong": { + "description": "Next-song playback control tooltip.", + "x-latin": "Susunod na kanta", + "x-review-status": "draft" + }, + "noSongsFound": "ᜏᜎᜅ᜔ ᜈᜑᜈᜉ᜔ ᜈ ᜃᜈ᜔ᜆ", + "@noSongsFound": { + "description": "Empty song list message.", + "x-latin": "Walang nahanap na kanta", + "x-review-status": "draft" + }, + "nowPlaying": "ᜃᜐᜎᜓᜃᜓᜌᜅ᜔ ᜆᜓᜋᜓᜆᜓᜄ᜔ᜆᜓᜄ᜔", + "@nowPlaying": { + "description": "Now-playing screen heading.", + "x-latin": "Kasalukuyang tumutugtog", + "x-review-status": "draft" + }, + "off": "ᜉᜆᜌ᜔", + "@off": { + "description": "Disabled/off mode label, including shuffle and repeat.", + "x-latin": "Patay", + "x-review-status": "draft" + }, + "pause": "ᜁᜑᜒᜈ᜔ᜆᜓ ᜋᜓᜈ", + "@pause": { + "description": "Temporarily pause playback; distinct from Stop.", + "x-latin": "Ihinto muna", + "x-review-status": "draft" + }, + "play": "ᜉᜆᜓᜄ᜔ᜆᜓᜄᜒᜈ᜔", + "@play": { + "description": "Start or resume playback.", + "x-latin": "Patugtugin", + "x-review-status": "draft" + }, + "playNext": "ᜁᜐᜓᜈᜓᜇ᜔", + "@playNext": { + "description": "Song action: insert immediately after the current song.", + "x-latin": "Isunod", + "x-review-status": "draft" + }, + "playlist2": "ᜆᜎᜀᜈ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ", + "@playlist2": { + "description": "Playback source label, not a user-created playlist name.", + "x-latin": "Talaan ng kanta", + "x-review-status": "draft" + }, + "playlists": "ᜋᜅ ᜆᜎᜀᜈ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ", + "@playlists": { + "description": "Playlist navigation tab and screen title.", + "x-latin": "Mga talaan ng kanta", + "x-review-status": "draft" + }, + "previousSong": "ᜈᜃᜇᜀᜅ᜔ ᜃᜈ᜔ᜆ", + "@previousSong": { + "description": "Previous-song playback control tooltip.", + "x-latin": "Nakaraang kanta", + "x-review-status": "draft" + }, + "previousSong2": "ᜈᜃᜇᜀᜅ᜔ ᜃᜈ᜔ᜆ", + "@previousSong2": { + "description": "Previous-song label in mini-player customization; match the playback control.", + "x-latin": "Nakaraang kanta", + "x-review-status": "draft" + }, + "queue": "ᜉᜒᜎ", + "@queue": { + "description": "Playback queue title and player action label.", + "x-latin": "Pila", + "x-review-status": "draft" + }, + "remove": "ᜀᜎᜒᜐᜒᜈ᜔", + "@remove": { + "description": "Remove from a queue/list; distinct from deleting a file.", + "x-latin": "Alisin", + "x-review-status": "draft" + }, + "repeat": "ᜂᜎᜒᜆ᜔: {arg1}", + "@repeat": { + "description": "Repeat-mode feedback. arg1 is the already-localized mode label.", + "x-latin": "Ulit: {arg1}", + "x-review-status": "draft" + }, + "repeatMode": "ᜉᜇᜀᜈ᜔ ᜈᜅ᜔ ᜉᜄ᜔-ᜂᜎᜒᜆ᜔", + "@repeatMode": { + "description": "Repeat-mode picker title.", + "x-latin": "Paraan ng pag-ulit", + "x-review-status": "draft" + }, + "search": "ᜑᜈᜉᜒᜈ᜔", + "@search": { + "description": "Search navigation tab and action.", + "x-latin": "Hanapin", + "x-review-status": "draft" + }, + "selectAll": "ᜉᜒᜎᜒᜁᜈ᜔ ᜎᜑᜆ᜔", + "@selectAll": { + "description": "Select every item without modifying its metadata.", + "x-latin": "Piliin lahat", + "x-review-status": "draft" + }, + "settings": "ᜋᜅ ᜉᜄ᜔ᜐᜐᜀᜌᜓᜐ᜔", + "@settings": { + "description": "Settings navigation tab and screen title. Review this terminology.", + "x-latin": "Mga pagsasaayos", + "x-review-status": "draft" + }, + "share": "ᜁᜊᜑᜄᜒ", + "@share": { + "description": "Share action.", + "x-latin": "Ibahagi", + "x-review-status": "draft" + }, + "shuffle": "ᜁᜑᜎᜓ", + "@shuffle": { + "description": "Shuffle-play action.", + "x-latin": "Ihalo", + "x-review-status": "draft" + }, + "shuffle2": "ᜉᜄ᜔ᜑᜎᜓ: {arg1}", + "@shuffle2": { + "description": "Shuffle-mode feedback. arg1 is the already-localized mode label.", + "x-latin": "Paghalo: {arg1}", + "x-review-status": "draft" + }, + "shuffleMode": "ᜉᜇᜀᜈ᜔ ᜈᜅ᜔ ᜉᜄ᜔ᜑᜎᜓ", + "@shuffleMode": { + "description": "Shuffle-mode picker title.", + "x-latin": "Paraan ng paghalo", + "x-review-status": "draft" + }, + "songs": "{arg1} • {arg2} ᜃᜈ᜔ᜆ", + "@songs": { + "description": "Album detail subtitle: arg1 is duration, arg2 is song count. Do not change either placeholder.", + "x-latin": "{arg1} • {arg2} kanta", + "x-review-status": "draft" + }, + "songs14": "ᜋᜅ ᜃᜈ᜔ᜆ", + "@songs14": { + "description": "Songs navigation tab and screen title.", + "x-latin": "Mga kanta", + "x-review-status": "draft" + }, + "songsCount": "{count, plural, =1{{count} ᜃᜈ᜔ᜆ} other{{count} ᜃᜈ᜔ᜆ}}", + "@songsCount": { + "description": "Recap song count. Tagalog counted nouns do not take English's plural suffix; both ICU branches intentionally use kanta.", + "x-latin": "{count, plural, =1{{count} kanta} other{{count} kanta}}", + "x-review-status": "draft" + }, + "stop": "ᜁᜑᜒᜈ᜔ᜆᜓ", + "@stop": { + "description": "Stop an operation, such as library scanning; distinct from Pause.", + "x-latin": "Ihinto", + "x-review-status": "draft" + }, + "tracks": "{_totalTracks} ᜃᜈ᜔ᜆ", + "@tracks": { + "description": "Album track count. Keep the underscore-prefixed placeholder unchanged.", + "x-latin": "{_totalTracks} kanta", + "x-review-status": "draft" + }, + "volume": "ᜎᜃᜐ᜔ ᜈᜅ᜔ ᜆᜓᜈᜓᜄ᜔", + "@volume": { + "description": "Playback volume label and player action.", + "x-latin": "Lakas ng tunog", + "x-review-status": "draft" + } +} diff --git a/lib/l10n/generated/app_localizations_tl.dart b/lib/l10n/generated/app_localizations_tl.dart new file mode 100644 index 00000000..91c7d5fa --- /dev/null +++ b/lib/l10n/generated/app_localizations_tl.dart @@ -0,0 +1,8138 @@ +// ignore: unused_import +import 'package:intl/intl.dart' as intl; +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Tagalog (`tl`). +class AppLocalizationsTl extends AppLocalizations { + AppLocalizationsTl([String locale = 'tl']) : super(locale); + + @override + String get aDraggableOverlayShowsWhileUsing => + 'A draggable overlay shows while using other apps'; + + @override + String get aLittleRecordOfWhatStayed => + 'A little record of what stayed on repeat.'; + + @override + String get aNewerFlickBuildIsOn => + 'A newer Flick build is on the Play Store.'; + + @override + String get aPlaylistWithThisNameAlready => + 'A playlist with this name already exists'; + + @override + String get aPremiumMusicPlayerWithCustom => + 'A premium music player with custom UAC 2.0 powered by Rust for the best audio experience.'; + + @override + String get aSmoothContinuousWaveAcrossFrequencies => + 'A smooth continuous wave across frequencies'; + + @override + String get aSongWithALongTitle => 'A song with a long title to preview'; + + @override + String get aTighterMixOfFavoritesAnd => + 'A tighter mix of favorites and the songs you keep circling back to.'; + + @override + String get aWeekAndCountingYourDedication => + 'A week and counting — your dedication shows.'; + + @override + String get aaudio => 'AAudio'; + + @override + String get aaudioAndroid81 => 'AAudio (Android 8.1+)'; + + @override + String get aaudioWithOpenslEsFallbackDefault => + 'AAudio with OpenSL ES fallback (default)'; + + @override + String get about => 'About'; + + @override + String get aboutFlickPlayer => 'About Flick Player'; + + @override + String get aboutThisAlbum => 'About this album'; + + @override + String get absoluteVolumeSync => 'Absolute Volume Sync'; + + @override + String get accentColor => 'Accent Color'; + + @override + String get accuraterip => 'AccurateRip'; + + @override + String achieved(Object arg1) { + return 'Achieved $arg1'; + } + + @override + String get achievementUnlocked => 'ACHIEVEMENT UNLOCKED'; + + @override + String get activateFallback => 'Activate Fallback'; + + @override + String get active => 'Active'; + + @override + String activeBands(Object activeCount) { + return '$activeCount active bands'; + } + + @override + String get activeDays => 'Active days'; + + @override + String get activeQueue => 'Active Queue'; + + @override + String get adaptive => 'Adaptive'; + + @override + String get add => 'Add'; + + @override + String get addAMusicFolderInSettings => 'Add a music folder in Settings'; + + @override + String get addANextTrackButton => 'Add a next-track button'; + + @override + String get addAPreviousTrackButton => 'Add a previous-track button'; + + @override + String get addAtLeastOneLyricLine => 'Add at least one lyric line first.'; + + @override + String get addDescription => 'Add Description'; + + @override + String get addDescription2 => 'Add description'; + + @override + String get addMusicFolder => 'Add Music Folder'; + + @override + String get addMusicFoldersInSettings => 'Add music folders in Settings'; + + @override + String get addMusicWithAlbumTagsTo => + 'Add music with album tags to see them here'; + + @override + String get addMusicWithArtistTagsTo => + 'Add music with artist tags to see them here'; + + @override + String get addServer => 'Add Server'; + + @override + String get addSongsFromThePlayerMenu => 'Add songs from the player menu'; + + @override + String get addSongsFromThePlayerOr => + 'Add songs from the player or song actions menu.'; + + @override + String addSongsToPlaylist(Object arg1) { + return 'Add $arg1 songs to playlist'; + } + + @override + String addSongsToPlaylist2(Object arg1) { + return 'Add $arg1 Songs to Playlist'; + } + + @override + String get addToFavorites => 'Add to favorites'; + + @override + String get addToFavorites2 => 'Add to Favorites'; + + @override + String get addToPlaylist => 'Add to playlist'; + + @override + String get addToPlaylist2 => 'Add to Playlist'; + + @override + String get addToQueue => 'Add to Queue'; + + @override + String get addToQueue2 => 'Add to queue'; + + @override + String addedSongsTo(Object arg1, Object arg2) { + return 'Added $arg1 songs to \"$arg2\"'; + } + + @override + String addedSongsTo2(Object arg1, Object playlistName) { + return 'Added $arg1 songs to $playlistName'; + } + + @override + String addedSongsToFavorites(Object arg1) { + return 'Added $arg1 songs to favorites'; + } + + @override + String addedSongsToFavorites3(Object arg1) { + return 'Added $arg1 songs to favorites'; + } + + @override + String addedTo(Object arg1) { + return 'Added to $arg1'; + } + + @override + String addedTo2(Object arg1) { + return 'Added to \"$arg1\"'; + } + + @override + String get addedToFavorites => 'Added to favorites'; + + @override + String addedToFavorites2(Object arg1) { + return 'Added \"$arg1\" to favorites'; + } + + @override + String get addsPreDriveAndCatchesPeaks => + 'Adds pre-drive and catches peaks against a final output ceiling.'; + + @override + String get adjustAudioFrequencies => 'Adjust audio frequencies'; + + @override + String get adjustMetadataTextSizeInArtwork => + 'Adjust metadata text size in artwork card mode'; + + @override + String get adjustMetadataTextSizeInImmersive => + 'Adjust metadata text size in immersive mode'; + + @override + String get adjustSpacingBetweenButtons => 'Adjust spacing between buttons'; + + @override + String get adjustTheMiniPlayerSurface => 'Adjust the mini player surface'; + + @override + String get adjustTheSizeOfTheBottom => 'Adjust the size of the bottom bar'; + + @override + String get adjustTheSizeOfTheIcons => 'Adjust the size of the icons'; + + @override + String get advanceToARandomCategory => 'Advance to a random category'; + + @override + String get advanceToTheNextCategoryAlphabetically => + 'Advance to the next category alphabetically'; + + @override + String get advanceToTheNextMostRecently => + 'Advance to the next most recently added category'; + + @override + String get advanced => 'Advanced'; + + @override + String get advancedMode => 'Advanced mode'; + + @override + String get afterHours => 'After Hours'; + + @override + String get afterScanningMatchFilesWithMissing => + 'After scanning, match files with missing tags against Apple Music. Only confident matches apply automatically.'; + + @override + String get air => 'Air'; + + @override + String get alacAudio => 'ALAC Audio'; + + @override + String alacBit(Object arg1) { + return 'ALAC $arg1-bit'; + } + + @override + String get album => 'Album'; + + @override + String get albumArt => 'Album Art'; + + @override + String get albumArt2 => 'Album art'; + + @override + String get albumArtImport => 'Album Art Import'; + + @override + String get albumArtist => 'Album Artist'; + + @override + String get albumArtists => 'Album Artists'; + + @override + String get albumArtwork => 'Album Artwork'; + + @override + String get albumColors => 'Album Colors'; + + @override + String get albumCount => 'Album Count'; + + @override + String get albumLimit => 'ALBUM LIMIT'; + + @override + String get albumName => 'Album Name'; + + @override + String get albumOptions => 'Album options'; + + @override + String get albums => 'Albums'; + + @override + String albums2(Object arg1) { + return '$arg1 albums'; + } + + @override + String albums3(Object _totalAlbums) { + return '$_totalAlbums albums'; + } + + @override + String get albumsShownPerPage => 'Albums shown per page'; + + @override + String albumsSongs(Object arg1, Object arg2) { + return '$arg1 albums • $arg2 songs'; + } + + @override + String get alignLyricTextToTheCenter => 'Align lyric text to the center'; + + @override + String get alignLyricTextToTheLeft => 'Align lyric text to the left edge'; + + @override + String get alignLyricTextToTheRight => 'Align lyric text to the right edge'; + + @override + String get all => 'All'; + + @override + String get allArtists => 'All Artists'; + + @override + String get allClearNoDuplicates => 'All clear — no duplicates'; + + @override + String get allDataIsStoredLocallyOn => + 'All data is stored locally on your device only: music library metadata, play history, playlists, equalizer presets, and app preferences. Last.fm credentials are stored securely on-device. This data never leaves your device unless you explicitly use an integration.'; + + @override + String get allFolders => 'All Folders'; + + @override + String get allFormats => 'All Formats'; + + @override + String get allFrequenciesEqually => 'All frequencies equally'; + + @override + String get allPass => 'All Pass'; + + @override + String get allResultsAreHiddenByActive => + 'All results are hidden by active filters.'; + + @override + String get allSongs => 'All Songs'; + + @override + String get allWordsStamped => 'All words stamped'; + + @override + String get allowFlickToRunWithoutAggressive => + 'Allow Flick to run without aggressive background limits so rescans and background features keep working'; + + @override + String get allowed => 'Allowed'; + + @override + String get alphabetical => 'Alphabetical'; + + @override + String get alphabeticalIndexRailOnTheSongs => + 'Alphabetical index rail on the songs screen'; + + @override + String get alsoRespectsYourSystemTextSize => + 'Also respects your system text size'; + + @override + String alt(Object arg1) { + return 'Alt $arg1'; + } + + @override + String get amber => 'Amber'; + + @override + String get analyzeLoudnessAndWriteReplaygainTags => + 'Analyze loudness and write ReplayGain tags for all songs'; + + @override + String get analyzingAudio => 'Analyzing audio'; + + @override + String get analyzingLoudness => 'Analyzing loudness'; + + @override + String get andArtwork => ' and artwork'; + + @override + String andMoreInRotation(Object arg1) { + return '$arg1 and more in rotation'; + } + + @override + String get android => 'Android'; + + @override + String get androidAudioApi => 'Android Audio API'; + + @override + String get androidBlockedWritingToThisFile => + 'Android blocked writing to this file. Remove and re-add the folder in Settings to grant edit access, then try again.'; + + @override + String get androidDeveloperOptionsTheReliableWay => + 'Android Developer Options — the reliable way to switch codec (in-app forcing uses a hidden system API that is blocked on stock Android)'; + + @override + String get androidDockRoute => 'Android dock route'; + + @override + String get androidManagedRustPlaybackPathUsing => + 'Android-managed Rust playback path using the native Oboe backend.'; + + @override + String get androidUsbRoute => 'Android USB route'; + + @override + String get animatedAlbumArt => 'Animated Album Art'; + + @override + String get animationStyle => 'Animation Style'; + + @override + String get animationStyleAndFrequencyFocus => + 'Animation style and frequency focus'; + + @override + String get animations => 'Animations'; + + @override + String get animationsAndHapticFeedback => 'Animations and haptic feedback'; + + @override + String get apiKey => 'API Key'; + + @override + String get appInfo => 'App Info'; + + @override + String get appTitle => 'Flick Player'; + + @override + String get appearance => 'Appearance'; + + @override + String get appearsInTheOverflowMenu => 'Appears in the overflow menu'; + + @override + String get appleMusicDataUnavailable => 'Apple Music data unavailable'; + + @override + String get appleMusicDataUpdated => 'Apple Music data updated'; + + @override + String get appleMusicLookupFailedCheckYour => + 'Apple Music lookup failed. Check your connection.'; + + @override + String get appleMusicMotionArtOnAlbums => + 'Apple Music Motion Art on albums plus pan/zoom, ambient glow and smooth fade on heroes'; + + @override + String appliedAutoeqFor(Object arg1) { + return 'Applied AutoEQ for $arg1'; + } + + @override + String get apply => 'Apply'; + + @override + String apply2(Object arg1) { + return 'Apply $arg1'; + } + + @override + String get applySelected => 'Apply Selected'; + + @override + String applyTo(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return 'Apply to $_temp0'; + } + + @override + String get applyingNewAudioEngine => 'Applying new audio engine…'; + + @override + String get apr => 'Apr'; + + @override + String get aptxAdaptive => 'aptX Adaptive'; + + @override + String get aptxHd => 'aptX HD'; + + @override + String get areYouSureYouWantTo => + 'Are you sure you want to delete this playlist?'; + + @override + String get areYouSureYouWantTo2 => + 'Are you sure you want to clear your entire listening history? This cannot be undone.'; + + @override + String get areYouSureYouWantTo3 => + 'Are you sure you want to reset all UAC2 preferences? This action cannot be undone.'; + + @override + String get artResolution => 'Art Resolution'; + + @override + String get artist => 'Artist'; + + @override + String get artistIsNotAvailableForThis => + 'Artist is not available for this song'; + + @override + String get artistName => 'Artist Name'; + + @override + String artistUnit(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'artists', + one: 'artist', + ); + return '$_temp0'; + } + + @override + String get artists => 'Artists'; + + @override + String artists2(Object arg1) { + return '$arg1 artists'; + } + + @override + String get artistsInRotation => 'Artists In Rotation'; + + @override + String get artwork => 'Artwork'; + + @override + String get artworkCacheCleared => 'Artwork cache cleared'; + + @override + String get artworkCard => 'Artwork Card'; + + @override + String get artworkPlacement => 'Artwork placement'; + + @override + String get artworkPlacement2 => 'Artwork Placement'; + + @override + String get artworkSize => 'Artwork size'; + + @override + String get artworkSize2 => 'Artwork Size'; + + @override + String get asmrDreams => 'ASMR Dreams'; + + @override + String atKhzBit(Object arg1, Object arg2) { + return ' at ${arg1}kHz/${arg2}bit'; + } + + @override + String get atLeastOneVersionMustStay => 'At least one version must stay.'; + + @override + String get attack => 'Attack'; + + @override + String get audio => 'Audio'; + + @override + String get audioFocus => 'Audio Focus'; + + @override + String get audioFormat => 'Audio Format'; + + @override + String get audioFormatIsDisabled => 'Audio Format is disabled'; + + @override + String get audioSignalPath => 'Audio Signal Path'; + + @override + String get audioTestingEquipment => 'Audio Testing Equipment'; + + @override + String get aug => 'Aug'; + + @override + String get auto => 'Auto'; + + @override + String get autoAdvance => 'Auto Advance'; + + @override + String get autoBeMsbDefaultOnlyChange => + 'Auto — BE-MSB default; only change if native DSD hisses'; + + @override + String get autoBitPerfectForUsbDacs => 'Auto Bit-perfect for USB DACs'; + + @override + String get autoCollapse => 'Auto Collapse'; + + @override + String get autoFill => 'Auto-fill'; + + @override + String get autoFocusSearch => 'Auto-Focus Search'; + + @override + String get autoFullView => 'Auto Full View'; + + @override + String get autoHideTimeout => 'Auto-hide Timeout'; + + @override + String get autoIdentifyUntaggedAlbums => 'Auto-identify untagged albums'; + + @override + String get autoNativeDsdOnDapsDop => + 'Auto — Native DSD on DAPs, DoP for USB DACs, PCM otherwise'; + + @override + String get autoReconnect => 'Auto-Reconnect'; + + @override + String get autoShowFullViewAfterInactivity => + 'Auto-show full view after inactivity'; + + @override + String get autoShowTheSpotifyStyleImmersive => + 'Auto-show the Spotify-style immersive full view after inactivity'; + + @override + String get autoU8ByteInterleavedRecommended => + 'Auto — U8 byte-interleaved (recommended)'; + + @override + String get autoeqHeadphones => 'AutoEQ headphones'; + + @override + String get autoeqHeadphones2 => 'AutoEQ Headphones'; + + @override + String get automatic => 'Automatic'; + + @override + String get automaticUpdateChecks => 'Automatic Update Checks'; + + @override + String get automaticallyOpenKeyboardWhenSwitchingTo => + 'Automatically open keyboard when switching to search'; + + @override + String get autoplayOnQueueEnd => 'Autoplay on Queue End'; + + @override + String get availableDevices => 'Available Devices'; + + @override + String b(Object arg1) { + return 'B$arg1'; + } + + @override + String get back => 'Back'; + + @override + String get backOnline => 'Back online'; + + @override + String get backToLocker => 'Back to Locker'; + + @override + String get backToReplay => 'Back to Replay'; + + @override + String get backend => 'Backend'; + + @override + String get background => 'Background'; + + @override + String get backgroundOpacity => 'Background Opacity'; + + @override + String get backgroundPlaybackAnchor => 'Background Playback Anchor'; + + @override + String get balance => 'Balance'; + + @override + String balance2(Object arg1) { + return 'Balance $arg1'; + } + + @override + String get balanceTempoDampFilterDelaysSize => + 'Balance, tempo, damp, filter, delays, size, mix, and extra spread controls.'; + + @override + String get balancedQualityAndStability => 'Balanced quality and stability'; + + @override + String get band => 'Band'; + + @override + String get bandControls => 'Band Controls'; + + @override + String get bandEditors => 'Band Editors'; + + @override + String get bandPass => 'Band Pass'; + + @override + String bandU2022(Object arg1, Object arg2) { + return 'Band $arg1 • $arg2'; + } + + @override + String bands(Object arg1) { + return '$arg1/31 bands'; + } + + @override + String bandsActive(Object activeCount, Object arg1) { + return '$activeCount/$arg1 bands active'; + } + + @override + String bandsAdjusted(Object adjustedBands) { + return '$adjustedBands bands adjusted'; + } + + @override + String bandsAdjusted2(Object adjustedCount, Object arg1) { + return '$adjustedCount/$arg1 bands adjusted'; + } + + @override + String bandsPreampDb(Object arg1, Object arg2, Object arg3) { + return '$arg1 bands · preamp $arg2 dB · $arg3'; + } + + @override + String get barHeight => 'Bar Height'; + + @override + String get bars => 'Bars'; + + @override + String get baseAlbumArtSizeForEach => + 'Base album-art size for each song card'; + + @override + String get bass => 'Bass'; + + @override + String get bassMidTreble => 'Bass, Mid & Treble'; + + @override + String get bassTreble => 'Bass + Treble'; + + @override + String battery(Object battery) { + return '$battery% battery'; + } + + @override + String get baybayinPilotDescription => + 'Experimental draft; untranslated text stays in English.'; + + @override + String get beLsbBigEndianSubslotLsb => + 'BE-LSB — big-endian subslot, LSB first'; + + @override + String get beMsbBigEndianSubslotMsb => + 'BE-MSB — big-endian subslot, MSB first (default)'; + + @override + String get beMsbPackingTheDefaultWire => + 'BE-MSB packing — the default wire convention'; + + @override + String get besideTheSong => 'Beside the song'; + + @override + String get bigEndian32BitSubslotMsb => + 'Big-endian 32-bit subslot, MSB-first bits'; + + @override + String get bigEndianSubslotLsbFirstBit => + 'Big-endian subslot, LSB-first (bit-reversed) bits'; + + @override + String bit(Object depth) { + return '${depth}bit'; + } + + @override + String get bitDepth => 'Bit depth'; + + @override + String get bitDepth2 => 'Bit Depth'; + + @override + String get bitDepths => 'Bit Depths'; + + @override + String get bitPerfect => 'BIT-PERFECT'; + + @override + String get bitPerfect2 => 'Bit-perfect'; + + @override + String get bitPerfectCapsule => 'Bit-Perfect Capsule'; + + @override + String get bitPerfectDapInternal => 'Bit-perfect (DAP Internal)'; + + @override + String get bitPerfectDapInternalDisabledSoftware => + 'Bit-perfect (DAP Internal) disabled — software effects active.'; + + @override + String get bitPerfectDapInternalEnabledAll => + 'Bit-perfect (DAP Internal) enabled — all DSP bypassed.'; + + @override + String get bitPerfectEnabledParametricEqIs => + 'Bit-perfect enabled — parametric EQ is bypassed on the direct USB path. Restart the app to apply playback changes.'; + + @override + String get bitPerfectUsbDac => 'Bit-perfect (USB DAC)'; + + @override + String get bitPerfectUsbDacCouldNot => + 'Bit-perfect (USB DAC) could not be enabled. Check the USB diagnostics for the failure reason.'; + + @override + String bitPerfectUsbDacCouldNot2(Object arg1) { + return 'Bit-perfect (USB DAC) could not be enabled for $arg1. Check the USB diagnostics.'; + } + + @override + String bitPerfectUsbDacEnabledFor(Object arg1) { + return 'Bit-perfect (USB DAC) enabled for $arg1.'; + } + + @override + String get bitPerfectVerified => 'Bit-perfect verified'; + + @override + String get bitSubslotsLlRrPer => '16-bit subslots: LL|RR per frame'; + + @override + String get bitSubslotsLlllRrrrPer => + '32-bit subslots: LLLL|RRRR per frame (legacy)'; + + @override + String get bitrateAdjustsToSignalQuality => + 'Bitrate adjusts to signal quality'; + + @override + String get blocked => 'Blocked'; + + @override + String get blue => 'Blue'; + + @override + String get bluetooth => 'Bluetooth'; + + @override + String get bluetoothCodecInfo => 'Bluetooth codec info'; + + @override + String get bluetoothOutput => 'Bluetooth output'; + + @override + String get boldSaturatedColorsFromAlbumArt => + 'Bold, saturated colors from album art.'; + + @override + String get boostBeyond100UpTo200 => 'Boost beyond 100% (up to 200%)'; + + @override + String get border => 'Border'; + + @override + String get bothBitPerfectOptionsAreOff => + 'Both bit-perfect options are off on this DAP, so the standard engine is unavailable. You can still use Rust via Oboe or Isochronous USB.'; + + @override + String get bottom => 'Bottom'; + + @override + String get bottomBar => 'Bottom Bar'; + + @override + String get bottomBarAlwaysVisible => 'Bottom Bar Always Visible'; + + @override + String get bouncy => 'Bouncy'; + + @override + String get browseByArtworkOpenAnyAlbum => + 'Browse by artwork, open any album, and jump straight into the tracklist.'; + + @override + String get browseMore => 'Browse More'; + + @override + String get browseTheFullControlsGuide => 'Browse the full controls guide'; + + @override + String get browseYourArtistLibrary => 'Browse your artist library'; + + @override + String get browseYourArtistsExploreTheirDiscographies => + 'Browse your artists, explore their discographies, and play their tracks.'; + + @override + String get buffer => 'Buffer'; + + @override + String build(Object kAppVersion, Object kAppBuild) { + return '$kAppVersion (build $kAppBuild)'; + } + + @override + String get buildFlavor => 'Build Flavor'; + + @override + String get buildFlavorFull => 'full — direct download build'; + + @override + String get buildFlavorPlay => 'play — Google Play build'; + + @override + String get buildingYourMusicHome => 'Building your music home'; + + @override + String get builtIn => 'Built-in'; + + @override + String get buttonSpacing => 'Button Spacing'; + + @override + String get buttons => 'Buttons'; + + @override + String get buyMeACoffee => 'Buy Me a Coffee'; + + @override + String by(Object arg1, Object arg2) { + return '\"$arg1\" by $arg2'; + } + + @override + String get bypassAllDspEqDynamicsCrossfade => + 'Bypass all DSP (EQ, dynamics, crossfade, speed) on the native DAP internal high-res path. Disable to use software effects. Turning off Bit-perfect (USB DAC) also disables this.'; + + @override + String get byteInterleavedLrlrStream => 'Byte-interleaved: LRLR stream'; + + @override + String get cacheWaveformsAndLoudnessForAll => + 'Cache waveforms and loudness for all songs'; + + @override + String cachedAlbumArtWillBeRemoved(Object arg1) { + return 'Cached album art ($arg1) will be removed. Artwork reloads automatically as you browse.'; + } + + @override + String cachedWavConversionsWillBeRemoved(Object size) { + return 'Cached WAV conversions ($size) will be removed. Files convert again on next playback.'; + } + + @override + String get calculatingSize => 'Calculating size...'; + + @override + String get calmFrequencies => 'Calm Frequencies'; + + @override + String get camera => 'Camera'; + + @override + String get cameraAccessIsNeededYouCan => + 'Camera access is needed. You can enable it in Android settings.'; + + @override + String get cameraAndPhotoLibraryAccessIs => + 'Camera and photo library access is used solely for the Flick Replay feature to create custom poster backgrounds for listening recap posters. Photos are only used at your explicit request and remain entirely on your device. No images are uploaded or transmitted.'; + + @override + String get cameraAndPhotos => 'Camera and Photos'; + + @override + String get cancel => 'Cancel'; + + @override + String get capAt60hzBalancedSmoothnessAnd => + 'Cap at 60Hz — balanced smoothness and battery'; + + @override + String capMs(Object arg1) { + return 'cap $arg1 ms'; + } + + @override + String get capabilities => 'Capabilities'; + + @override + String get capabilitiesNotAvailable => 'Capabilities not available'; + + @override + String get capabilityState => 'Capability State'; + + @override + String get cardSize => 'Card Size'; + + @override + String get cardWidth => 'Card Width'; + + @override + String get cast => 'Cast'; + + @override + String get casting => 'Casting'; + + @override + String get castingTapToManage => 'Casting — tap to manage'; + + @override + String castingTo(Object deviceName) { + return 'Casting to $deviceName'; + } + + @override + String castingTo2(Object arg1) { + return 'Casting to $arg1'; + } + + @override + String get categories => 'Categories'; + + @override + String get ceiling => 'Ceiling'; + + @override + String get center => 'Center'; + + @override + String get centerTheTitleAndInfoIn => + 'Center the title and info in the detail header'; + + @override + String get centeredHeaderTitle => 'Centered Header Title'; + + @override + String get centeredWidensToFitYourControls => + 'Centered; widens to fit your controls'; + + @override + String ch(Object channels) { + return '$channels ch'; + } + + @override + String ch2(Object ch) { + return '$ch ch'; + } + + @override + String ch3(Object arg1, Object arg2) { + return '$arg1 / ${arg2}ch'; + } + + @override + String get changingSampleRateBitDepthOr => + 'Changing sample rate, bit depth, or channel handling can resample songs and may affect playback quality, pitch, speed, or stability on some devices.'; + + @override + String get channels => 'Channels'; + + @override + String channels2(Object arg1) { + return '$arg1 channels'; + } + + @override + String channels3(Object ch) { + return '$ch channels'; + } + + @override + String get checkAgain => 'Check Again'; + + @override + String get checkTheVersionsYouWantTo => + 'Check the versions you want to keep — unchecked ones will be removed from your library. At least one must stay.'; + + @override + String get checkVersionsToKeepUncheckedWill => + 'Check versions to keep — unchecked will be removed'; + + @override + String get checking => 'Checking…'; + + @override + String get checkingForUpdates => 'Checking for Updates'; + + @override + String get checkingForUpdates2 => 'Checking for Updates...'; + + @override + String get childrenSPrivacy => 'Children\'s Privacy'; + + @override + String get chooseAction => 'Choose Action'; + + @override + String get chooseAudioEngine => 'Choose Audio Engine'; + + @override + String get chooseLocationU2026 => 'Choose location…'; + + @override + String get chooseWhichToKeep => 'Choose which to keep'; + + @override + String get chromecast => 'Chromecast'; + + @override + String get circularDotsRadiusFollowsAmplitude => + 'Circular dots — radius follows amplitude'; + + @override + String get cityBeats => 'City Beats'; + + @override + String get claimedByFlick => 'Claimed by Flick'; + + @override + String get cleanStraightLineWithPrecisionScrubbing => + 'Clean straight line with precision scrubbing.'; + + @override + String get clear => 'Clear'; + + @override + String get clearAll => 'Clear All'; + + @override + String get clearAllUac2Settings => 'Clear all UAC2 settings'; + + @override + String get clearArtworkCache => 'Clear Artwork Cache?'; + + @override + String get clearArtworkCache2 => 'Clear Artwork Cache'; + + @override + String get clearConvertedAudio => 'Clear Converted Audio'; + + @override + String get clearConvertedAudioCache => 'Clear Converted Audio Cache?'; + + @override + String get clearFilters => 'Clear filters'; + + @override + String get clearHistory => 'Clear History'; + + @override + String get clearLogs => 'Clear logs?'; + + @override + String get clearTheCounterAndAnyUnlocked => + 'Clear the counter and any unlocked streak milestones'; + + @override + String get clearWord => 'Clear Word'; + + @override + String get clearWords => 'Clear Words'; + + @override + String get clearing => 'Clearing...'; + + @override + String get close => 'Close'; + + @override + String get closePreview => 'Close preview'; + + @override + String codecApplied(Object arg1) { + return 'Codec applied: $arg1'; + } + + @override + String get codecControl => 'Codec Control'; + + @override + String get codecForcingUnavailableOnThisDevice => + 'Codec forcing unavailable on this device — set it via Developer Options → Bluetooth Audio Codec.'; + + @override + String get codecInfo => 'Codec Info'; + + @override + String get codecU0026Audio => 'Codec & Audio'; + + @override + String get collapseAfter => 'Collapse After'; + + @override + String get collapsed => 'Collapsed'; + + @override + String get collection => 'Collection'; + + @override + String get color => 'Color'; + + @override + String get comingSoon => 'Coming Soon'; + + @override + String get compatibility => 'Compatibility'; + + @override + String get compatibleWithPowerampEq => 'Compatible with Poweramp EQ'; + + @override + String get completelyHiddenFromTheBottomBar => + 'Completely hidden from the bottom bar'; + + @override + String get compressor => 'Compressor'; + + @override + String get compressorOff => 'Compressor off'; + + @override + String get compressorOn => 'Compressor on'; + + @override + String get configureUsbDacAmpDevices => 'Configure USB DAC/AMP devices'; + + @override + String get configureYourMusicExperience => 'Configure your music experience'; + + @override + String get connect => 'Connect'; + + @override + String get connectAMusicServer => 'Connect a music server'; + + @override + String get connectASubsonicJellyfinWebdavUpnp => + 'Connect a Subsonic, Jellyfin, WebDAV, UPnP, or Tidal server to stream your remote library.'; + + @override + String get connectAUsbDacOrAudio => 'Connect a USB DAC or audio interface'; + + @override + String get connectListenbrainz => 'Connect ListenBrainz'; + + @override + String get connectToScrobbleYourListeningHistory => + 'Connect to scrobble your listening history'; + + @override + String get connectToScrobbleYourMusic => 'Connect to scrobble your music'; + + @override + String get connectToSubmitYourListeningHistory => + 'Connect to submit your listening history'; + + @override + String get connectToTheInternetToCheck => + 'Connect to the internet to check for updates.'; + + @override + String get connected => 'Connected'; + + @override + String get connectedAccount => 'Connected Account'; + + @override + String connectedAs(Object username) { + return 'Connected as $username'; + } + + @override + String get connecting => 'Connecting'; + + @override + String get connection => 'Connection'; + + @override + String get connectionBehavior => 'Connection Behavior'; + + @override + String get connectionFailedRetry => 'Connection Failed — Retry'; + + @override + String get connectionManagement => 'Connection Management'; + + @override + String get connectionNotices => 'Connection notices'; + + @override + String get connectionNoticesDescription => + 'Show offline and back-online notices'; + + @override + String get connectionOk => 'Connection OK'; + + @override + String get connectionStatus => 'Connection Status'; + + @override + String containsValuesOutsideTheSupportedRanges(Object presetName) { + return '\"$presetName\" contains values outside the supported ranges; these were adjusted:'; + } + + @override + String get content => 'Content'; + + @override + String get contentControls => 'Content & Controls'; + + @override + String get contentPlacement => 'Content placement'; + + @override + String get contentPlacement2 => 'Content Placement'; + + @override + String get continueLabel => 'Continue'; + + @override + String get continueThroughTheSearchResults => + 'Continue through the search results'; + + @override + String get continueThroughYourEntireLibrary => + 'Continue through your entire library'; + + @override + String conversionFailed(Object error) { + return 'Conversion failed: $error'; + } + + @override + String get convertedAudioCacheCleared => 'Converted audio cache cleared'; + + @override + String convertedSuccessfully(Object fileName) { + return '$fileName converted successfully'; + } + + @override + String get convertingAudio => 'Converting audio...'; + + @override + String convertingToWav(Object fileName) { + return 'Converting $fileName to WAV...'; + } + + @override + String get convolverImpulseResponse => 'Convolver / Impulse Response'; + + @override + String copies(Object arg1, Object arg2) { + return '$arg1 • $arg2 copies'; + } + + @override + String get copy => 'Copy'; + + @override + String get copyLink => 'Copy link'; + + @override + String get copyYourUserTokenFromListenbrainz => + 'Copy your user token from ListenBrainz settings and paste it below.'; + + @override + String get copyright => 'Copyright'; + + @override + String get cornerRadius => 'Corner Radius'; + + @override + String get cosmicOrchestra => 'Cosmic Orchestra'; + + @override + String get couldNotCheckForUpdates => 'Could Not Check for Updates'; + + @override + String get couldNotConnectToLastFm => + 'Could not connect to Last.fm. Check your API credentials and try again.'; + + @override + String get couldNotConnectToListenbrainzCheck => + 'Could not connect to ListenBrainz. Check your token and try again.'; + + @override + String get couldNotLoadAlbumSongs => 'Could not load album songs'; + + @override + String get couldNotCreateThePosterImage => + 'Could not create the poster image.'; + + @override + String get couldNotLoadArtistSongs => 'Could not load artist songs'; + + @override + String couldNotLoadIr(Object e) { + return 'Could not load IR: $e'; + } + + @override + String get couldNotLoadSession => 'Could not load session'; + + @override + String get couldNotOpenBrowser => 'Could not open browser.'; + + @override + String get couldNotOpenKoFiPlease => + 'Could not open Ko-fi. Please try again.'; + + @override + String get couldNotOpenLink => 'Could not open link'; + + @override + String couldNotOpenLink2(Object e) { + return 'Could not open link: $e'; + } + + @override + String get couldNotOpenThatPhotoTry => + 'Could not open that photo. Try another image.'; + + @override + String get couldNotOpenTheLink => 'Could not open the link'; + + @override + String couldNotOpenTheLink2(Object e) { + return 'Could not open the link: $e'; + } + + @override + String get couldNotOpenThePlayStore => 'Could not open the Play Store.'; + + @override + String couldNotOpenThePlayStore2(Object error) { + return 'Could not open the Play Store: $error'; + } + + @override + String get couldNotOpenThePlayStore3 => 'Could not open the Play Store'; + + @override + String get couldNotReadTheCoverColors => + 'Could not read the cover colors. Signal is still available.'; + + @override + String get couldNotReadTheSelectedLyrics => + 'Could not read the selected lyrics file.'; + + @override + String get couldNotSaveTheLyricsFile => 'Could not save the lyrics file.'; + + @override + String get couldNotSaveYourRecapPlease => + 'Could not save your recap. Please try again.'; + + @override + String get couldNotUseTheSelectedLyrics => + 'Could not use the selected lyrics file.'; + + @override + String get couldnTOpenTheBrowserAutomatically => + 'Couldn\'t open the browser automatically. Authorize on any device with this link — we\'ll finish signing in once you do:'; + + @override + String get countingFiles => 'Counting files…'; + + @override + String covers(Object done, Object total) { + return '$done / $total covers'; + } + + @override + String get create => 'Create'; + + @override + String get createACollection => 'Create a collection'; + + @override + String get createACustomPreset => 'Create a custom preset'; + + @override + String get createAPlaylistImportAnM3u => + 'Create a playlist, import an M3U, or let the mixes above carry the session.'; + + @override + String get createLyrics => 'Create Lyrics'; + + @override + String get createNewPlaylist => 'Create new playlist'; + + @override + String get createNewPlaylist2 => 'Create New Playlist'; + + @override + String get createOrRefreshPlaylistsFoundInside => + 'Create or refresh playlists found inside scanned folders'; + + @override + String get createPlaylist => 'Create Playlist'; + + @override + String get createPlaylistFromSelected => 'Create playlist from selected'; + + @override + String get createYourFirstPlaylistOrJump => + 'Create your first playlist or jump into your saved collections.'; + + @override + String get createYourFirstPlaylistToOrganize => + 'Create your first playlist to organize\nyour favorite songs'; + + @override + String created(Object arg1) { + return 'Created $arg1'; + } + + @override + String createdAndAddedSong(Object arg1) { + return 'Created $arg1 and added song'; + } + + @override + String createdAndAddedSongs(Object name, Object arg1) { + return 'Created $name and added $arg1 songs'; + } + + @override + String get creativeFx => 'Creative FX'; + + @override + String credentialsRejectedByReEnterThe(Object arg1) { + return 'Credentials rejected by $arg1. Re-enter the password.'; + } + + @override + String get credentialsSavedSuccessfully => 'Credentials saved successfully!'; + + @override + String get crispestHeavierDuringFastScrolling => + 'Crispest — heavier during fast scrolling'; + + @override + String get crossfade => 'Crossfade'; + + @override + String get crossfadeIsMostReliableOnThe => + 'Crossfade is most reliable on the Standard engine. On the high-quality (Rust) engine it can be unstable — switch to Standard for consistent crossfades.'; + + @override + String get crossfeed => 'Crossfeed'; + + @override + String get crossfeedBs2b => 'Crossfeed (BS2B)'; + + @override + String get crossfeedEasy => 'Crossfeed easy'; + + @override + String get crossfeedRunsOnTheHighQuality => + 'Crossfeed runs on the high-quality (Rust) engine only. The Standard engine plays without it.'; + + @override + String get crystalCaverns => 'Crystal Caverns'; + + @override + String get cueSheetTracksCannotBeEdited => + 'CUE sheet tracks cannot be edited.'; + + @override + String get cueSheetTracksCannotBeEdited2 => + 'CUE sheet tracks cannot be edited'; + + @override + String get currentArtwork => 'Current artwork'; + + @override + String get currentCustomArt => 'Current custom art'; + + @override + String get currentPlaybackMode => 'Current Playback Mode'; + + @override + String currentRoute(Object arg1) { + return 'Current route: $arg1.'; + } + + @override + String get currentSongPreviewOnly => 'Current song · preview only'; + + @override + String get currentStreak => 'Current Streak'; + + @override + String get curvature => 'Curvature'; + + @override + String get curvatureSizingDepthAndVisuals => + 'Curvature, sizing, depth, and visuals'; + + @override + String get curve => 'Curve'; + + @override + String get curveOfTheOrbitArcHigher => + 'Curve of the orbit arc — higher is gentler'; + + @override + String get curvePreview => 'Curve Preview'; + + @override + String get curvedWave => 'Curved Wave'; + + @override + String get custom => 'Custom'; + + @override + String get customFormat => 'Custom Format'; + + @override + String get customFormatForcesPlaybackToThe => + 'Custom format forces playback to the selected output format. If the chosen sample rate, bit depth, or channels do not suit the song or device, you may hear altered sound, pitch, speed, or instability.'; + + @override + String get customFormatIsDisabledInBit => + 'Custom format is disabled in Bit-perfect (USB DAC) mode because exact sample rate matching is required. Disable Bit-perfect (USB DAC) to set custom formats.'; + + @override + String get customFormatIsUnavailableBecauseAudio => + 'Custom format is unavailable because Audio Format is disabled in Settings.'; + + @override + String get customWidth => 'Custom Width'; + + @override + String get customizeAudioDisplayNavigationAnd => + 'Customize audio, display, navigation, and integrations.'; + + @override + String get customizeBottomBar => 'Customize Bottom Bar'; + + @override + String get customizeHomeScreenWidgets => 'Customize home screen widgets'; + + @override + String get customizeOrbital => 'Customize Orbital'; + + @override + String get customizeWhichTabsAppearAndTheir => + 'Customize which tabs appear and their size'; + + @override + String dAgo(Object arg1) { + return '${arg1}d ago'; + } + + @override + String dAgo2(Object arg1) { + return '${arg1}d ago'; + } + + @override + String get dacClaim => 'DAC Claim'; + + @override + String dacWillBeOfferedAgain(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count DACs', + one: '$count DAC', + ); + return '$_temp0 will be offered again.'; + } + + @override + String get daily => 'Daily'; + + @override + String get damp => 'Damp'; + + @override + String get dapNativeBitOrder => 'DAP Native Bit Order'; + + @override + String get dapNativeByteGrouping => 'DAP Native Byte Grouping'; + + @override + String get dark => 'Dark'; + + @override + String get dataCollection => 'Data Collection'; + + @override + String get date => 'Date'; + + @override + String get dateAdded => 'Date Added'; + + @override + String get dateAddedNewest => 'Date Added (Newest)'; + + @override + String get dateAddedOldest => 'Date Added (Oldest)'; + + @override + String get dayStreak => 'day streak'; + + @override + String get dayStreak2 => 'Day streak'; + + @override + String get dayStreak3 => 'Day Streak'; + + @override + String get dayStreaks => 'Day Streaks'; + + @override + String dayUnit(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'days', + one: 'day', + ); + return '$_temp0'; + } + + @override + String db10(Object arg1) { + return '$arg1 dB'; + } + + @override + String db13(Object arg1) { + return '$arg1 dB'; + } + + @override + String db15(Object arg1, Object arg2) { + return '$arg1% $arg2 dB'; + } + + @override + String db2(Object value) { + return '$value dB'; + } + + @override + String db9(Object arg1) { + return '$arg1 dB'; + } + + @override + String dbCut(Object arg1) { + return '$arg1 dB cut'; + } + + @override + String dbMax(Object arg1) { + return '$arg1 dB max'; + } + + @override + String get deactivateFallback => 'Deactivate Fallback'; + + @override + String get dec => 'Dec'; + + @override + String get decode => 'Decode'; + + @override + String get decodeSongsAfterScanningToCache => + 'Decode songs after scanning to cache waveform peaks and loudness metrics'; + + @override + String get deepEarth => 'Deep Earth'; + + @override + String get deepScan => 'Deep Scan'; + + @override + String get deepScanOff => 'Deep scan off'; + + @override + String get deepScanOn => 'Deep scan on'; + + @override + String get defaultAndroidPlaybackEngineUsedBy => + 'Default Android playback engine used by Flick right now.'; + + @override + String get defaultAndroidPlayerPlaysEverything => + 'Default Android player — plays everything reliably. The safest choice for most listeners.'; + + @override + String get defaultLabel => 'Default'; + + @override + String get del => 'Del'; + + @override + String get delays => 'Delays'; + + @override + String get delete => 'Delete'; + + @override + String deleteAndAllSongsAndPlaylists(Object arg1) { + return 'Delete \"$arg1\" and all songs and playlists synced from it? Cached downloads are kept.'; + } + + @override + String get deleteFile => 'Delete File'; + + @override + String get deleteFiles => 'Delete Files'; + + @override + String get deletePlaylist => 'Delete Playlist'; + + @override + String get deletePreset => 'Delete Preset?'; + + @override + String get deleteSelected => 'Delete selected'; + + @override + String get deleteSong => 'Delete Song'; + + @override + String get deleteSong2 => 'Delete Song?'; + + @override + String get deleteSong3 => 'Delete song'; + + @override + String deleteSongs(Object arg1) { + return 'Delete $arg1 songs?'; + } + + @override + String get deleteSongs2 => 'Delete songs'; + + @override + String deleteThisCannotBeUndone(Object arg1) { + return 'Delete \"$arg1\"? This cannot be undone.'; + } + + @override + String deleted(Object arg1) { + return 'Deleted \"$arg1\"'; + } + + @override + String deletedSongs(Object arg1) { + return 'Deleted $arg1 songs'; + } + + @override + String get depth => 'Depth'; + + @override + String get deselectAll => 'Deselect all'; + + @override + String get designed => 'Designed'; + + @override + String get detailScreens => 'Detail Screens'; + + @override + String get details => 'Details'; + + @override + String get developerMode => 'Developer Mode'; + + @override + String get developerOptionsIsDisabledEnableIt => + 'Developer Options is disabled. Enable it via Settings → About phone (tap Build number 7 times), then retry.'; + + @override + String get device => 'Device'; + + @override + String get deviceCapabilities => 'Device Capabilities'; + + @override + String get deviceConnected => 'Device connected'; + + @override + String get deviceDac => 'Device DAC'; + + @override + String get deviceDacVolume => 'Device DAC Volume'; + + @override + String get deviceDisconnected => 'Device disconnected'; + + @override + String get deviceInformation => 'Device Information'; + + @override + String get deviceType => 'Device Type'; + + @override + String get devices => 'Devices'; + + @override + String get direct => 'Direct'; + + @override + String get directAlsaOutputIsActiveAnd => + 'Direct ALSA output is active and bypassing the Android audio server.'; + + @override + String get directLibusbIsochronousUsbEngineBest => + 'Direct libusb isochronous USB engine. Best paired with Bit-perfect (USB DAC) for verified external DAC playback.'; + + @override + String get directUsb => 'Direct USB'; + + @override + String get directUsbDeviceManaged => 'Direct USB device-managed'; + + @override + String get directUsbExperimental => 'Direct USB experimental'; + + @override + String get disableBatteryOptimization => 'Disable Battery Optimization'; + + @override + String get disableBatteryOptimizationRecommended => + 'Disable Battery Optimization (Recommended)'; + + @override + String get disabled => 'Disabled'; + + @override + String get disabledInBitPerfectMode => 'Disabled in bit-perfect mode'; + + @override + String get disabledInBitPerfectUsbDac => + 'Disabled in Bit-perfect (USB DAC) mode (exact rate required)'; + + @override + String get disabledWhileBothBitPerfectOptions => + 'Disabled while both bit-perfect options are off on this DAP.'; + + @override + String get disc => 'Disc'; + + @override + String get disc2 => 'Disc #'; + + @override + String get discard => 'Discard'; + + @override + String get discardChanges => 'Discard changes?'; + + @override + String get discardChanges2 => 'Discard Changes?'; + + @override + String get disconnect => 'Disconnect'; + + @override + String get disconnectBehaviorAndCodecInfo => + 'Disconnect behavior and codec info'; + + @override + String disconnectFrom(Object arg1) { + return 'Disconnect from $arg1'; + } + + @override + String get disconnectLastFm => 'Disconnect Last.fm?'; + + @override + String get disconnectListenbrainz => 'Disconnect ListenBrainz?'; + + @override + String get discord => 'Discord'; + + @override + String get discoversDlnaUpnpAndChromecastReceivers => + 'Discovers DLNA, UPnP and Chromecast receivers on your network'; + + @override + String get dismiss => 'Dismiss'; + + @override + String get display => 'Display'; + + @override + String get displayFileFormatAndBitrateIn => + 'Display file format and bitrate in immersive mode'; + + @override + String get displayFileFormatAndBitrateIn2 => + 'Display file format and bitrate in artwork card mode'; + + @override + String get displayTextLabelsBelowIcons => 'Display text labels below icons'; + + @override + String get displayTheAlbumNameInArtwork => + 'Display the album name in artwork card mode'; + + @override + String get displayTheArtistNameInArtwork => + 'Display the artist name in artwork card mode'; + + @override + String get displayTheArtistNameInImmersive => + 'Display the artist name in immersive mode'; + + @override + String get displayTheTrackTitleInArtwork => + 'Display the track title in artwork card mode'; + + @override + String get displayTheTrackTitleInImmersive => + 'Display the track title in immersive mode'; + + @override + String get distanceBetweenSongsAlongTheArc => + 'Distance between songs along the arc'; + + @override + String get dlnaAndUpnpReceiversAreControlled => + 'DLNA and UPnP receivers are controlled directly in pure Dart — no extra dependencies. Chromecast support uses the native Cast SDK. Network sources (Subsonic, WebDAV, Jellyfin, UPnP), local files, and cached songs can all be cast — locals are served straight from this phone. While casting, volume keys and the system volume panel control the connected device.'; + + @override + String get dlnaUpnp => 'DLNA / UPnP'; + + @override + String get dlnaUpnpAndChromecastReceivers => + 'DLNA, UPnP and Chromecast receivers'; + + @override + String get donTShowAgainToday => 'Don\'t show again today'; + + @override + String get donate => 'Donate'; + + @override + String get donateFundFeaturesAndKeepThe => + 'Donate, fund features, and keep the app alive'; + + @override + String get done => 'Done'; + + @override + String get dop => 'DoP'; + + @override + String get dots => 'Dots'; + + @override + String get doubleTapABandToReset => 'Double-tap a band to reset'; + + @override + String get doubleTapToReset => 'Double-tap to reset'; + + @override + String get doubleTapToResetThisBand => 'Double-tap to reset this band'; + + @override + String down(Object arg1) { + return '$arg1 down'; + } + + @override + String get downloadTheLatestApkFromFlick => + 'Download the latest APK from flick-player.site'; + + @override + String get downloadUpdate => 'Download Update'; + + @override + String dp(Object arg1) { + return '$arg1 dp'; + } + + @override + String dp2(Object arg1) { + return '$arg1 dp'; + } + + @override + String dp3(Object arg1) { + return '$arg1 dp'; + } + + @override + String get dragABoundaryToStretchOr => + 'Drag a boundary to stretch or shrink the word before it. The last boundary moves the next line.'; + + @override + String get dragBandsUpOrDown => 'Drag bands up or down'; + + @override + String get dragToChangeFrequencyGain => 'Drag to change frequency & gain'; + + @override + String get dragToMovePinchToWiden => 'Drag to move • Pinch to widen/narrow'; + + @override + String get dragVerticallyToChangeGain => 'Drag vertically to change gain'; + + @override + String get drawTheCurvedArcBehindThe => + 'Draw the curved arc behind the songs'; + + @override + String driftMs(Object arg1) { + return 'Drift $arg1 ms'; + } + + @override + String get dsdDsfPlayback => 'DSD / DSF Playback'; + + @override + String get dsdMode => 'DSD mode'; + + @override + String get dsdOutputMode => 'DSD Output Mode'; + + @override + String get dsdStream => 'DSD stream'; + + @override + String get duckOnNotifications => 'Duck on Notifications'; + + @override + String get duplicateCleaner => 'Duplicate Cleaner'; + + @override + String get duplicatesRemovedUsingRecommendedPicks => + 'Duplicates removed using recommended picks.'; + + @override + String get duration => 'Duration'; + + @override + String get durationMatch => 'Duration Match'; + + @override + String get dynamics => 'Dynamics'; + + @override + String get earlier => 'Earlier'; + + @override + String get earlierStandoutsPulledBackIntoView => + 'Earlier standouts pulled back into view from your listening history.'; + + @override + String get editCredentials => 'Edit Credentials'; + + @override + String get editDescription => 'Edit Description'; + + @override + String get editDescription2 => 'Edit description'; + + @override + String get editMetadata => 'Edit Metadata'; + + @override + String get editServer => 'Edit Server'; + + @override + String get editSync => 'Edit & Sync'; + + @override + String get editText => 'Edit Text'; + + @override + String get editToken => 'Edit Token'; + + @override + String get empty => 'Empty'; + + @override + String get emptyLine => '(Empty line)'; + + @override + String get emptyTheLibraryFilesOnDisk => + 'Empty the library; files on disk are kept'; + + @override + String get enable => 'Enable'; + + @override + String get enable432HzTuning => 'Enable 432 Hz Tuning?'; + + @override + String get enableAnimatedTransitionsAndEffects => + 'Enable animated transitions and effects'; + + @override + String get enableEqToEdit => 'Enable EQ to edit'; + + @override + String get enableFullLibraryAccess => 'Enable Full Library Access'; + + @override + String get enableVibrationOnInteractions => + 'Enable vibration on interactions'; + + @override + String get enabled => 'Enabled'; + + @override + String get endpoint => 'Endpoint'; + + @override + String get engine => 'Engine'; + + @override + String get engineSelector => 'Engine Selector'; + + @override + String get english => 'English'; + + @override + String enterAValidNumber(Object label) { + return 'Enter a valid $label number'; + } + + @override + String enterAValueFromTo(Object arg1, Object arg2) { + return 'Enter a value from $arg1% to $arg2%'; + } + + @override + String get enterAYear19999 => 'Enter a year (1–9999)'; + + @override + String get enterYourApiKey => 'Enter your API key'; + + @override + String get enterYourSharedSecret => 'Enter your shared secret'; + + @override + String ep(Object arg1) { + return 'EP $arg1'; + } + + @override + String get eqDynamics => 'EQ & Dynamics'; + + @override + String get equalPower => 'Equal Power'; + + @override + String get equalizer => 'Equalizer'; + + @override + String error(Object error) { + return 'Error: $error'; + } + + @override + String error2(Object arg1) { + return 'Error: $arg1'; + } + + @override + String get error3 => 'Error'; + + @override + String errorLoadingCapabilities(Object error) { + return 'Error loading capabilities: $error'; + } + + @override + String get errorLoadingPlaylists => 'Error loading playlists'; + + @override + String errorLoadingPlaylists2(Object error) { + return 'Error loading playlists: $error'; + } + + @override + String get errorLoadingPreference => 'Error loading preference'; + + @override + String get errorLoadingSongs => 'Error loading songs'; + + @override + String get etherealTones => 'Ethereal Tones'; + + @override + String get everyAlbumHasArtistAndAlbum => + 'Every album has artist and album tags.'; + + @override + String get everySongIsRemovedFromYour => + 'Every song is removed from your library. Files on disk are kept; rescan your folders to add them again.'; + + @override + String get exactMatch => 'Exact Match'; + + @override + String get excludeTinyClipsPreviewsAndAccidental => + 'Exclude tiny clips, previews, and accidental scraps'; + + @override + String get exclusiveDirectPcmIsActiveAnd => + 'Exclusive direct PCM is active and bypassing the Android mixer at the track\'s native rate.'; + + @override + String get exclusiveUsbBitPerfectReEngaged => + 'Exclusive USB bit-perfect re-engaged.'; + + @override + String get exclusiveUsbDroppedToTheAndroid => + 'Exclusive USB dropped to the Android mixer. Bit-perfect is paused.'; + + @override + String get exclusiveUsbIsActiveAndBypassing => + 'Exclusive USB is active and bypassing the Android mixer.'; + + @override + String get exclusiveUsbIsStillUnavailableCheck => + 'Exclusive USB is still unavailable. Check the USB diagnostics.'; + + @override + String get expanded => 'Expanded'; + + @override + String get expandedHeaderArt => 'Expanded Header Art'; + + @override + String get experimental => 'Experimental'; + + @override + String get experimentalDownTunePlaybackBy432 => + 'Experimental — down-tune playback by 432/440. This disables bit-perfect passthrough and runs the DSP path.'; + + @override + String get exportAsM3u => 'Export as .m3u'; + + @override + String get exportAsM3u8 => 'Export as .m3u8'; + + @override + String get exportCsv => 'Export CSV'; + + @override + String get exportCurrentPreset => 'Export current preset'; + + @override + String get exportEqualizerPreset => 'Export equalizer preset'; + + @override + String exportFailed(Object e) { + return 'Export failed: $e'; + } + + @override + String get exportFormat => 'Export format'; + + @override + String get exportTxt => 'Export TXT'; + + @override + String exportedPresetTo(Object savePath) { + return 'Exported preset to $savePath'; + } + + @override + String exportedPresetTo2(Object fallbackPath) { + return 'Exported preset to $fallbackPath'; + } + + @override + String exportedSongsTo(Object arg1, Object arg2) { + return 'Exported $arg1 songs to \"$arg2\".'; + } + + @override + String get extendedVolume => 'Extended Volume'; + + @override + String get externalLabel => 'External'; + + @override + String get externalSongsCannotBeEdited => 'External songs cannot be edited.'; + + @override + String get externalSongsCannotBeEdited2 => 'External songs cannot be edited'; + + @override + String get extraCovers => 'Extra covers'; + + @override + String get failedToActivateFallback => 'Failed to activate fallback'; + + @override + String failedToAddFolder(Object e) { + return 'Failed to add folder: $e'; + } + + @override + String failedToAddToFavorites(Object arg1) { + return 'Failed to add \"$arg1\" to favorites'; + } + + @override + String failedToClearCache(Object e) { + return 'Failed to clear cache: $e'; + } + + @override + String get failedToDeactivateFallback => 'Failed to deactivate fallback'; + + @override + String get failedToImportPresetFile => 'Failed to import preset file.'; + + @override + String failedToOpenAllFilesAccess(Object e) { + return 'Failed to open All Files Access settings: $e'; + } + + @override + String failedToOpenBatteryOptimizationSettings(Object e) { + return 'Failed to open battery optimization settings: $e'; + } + + @override + String failedToRemoveFolder(Object e) { + return 'Failed to remove folder: $e'; + } + + @override + String failedToRemoveSongs(Object e) { + return 'Failed to remove songs: $e'; + } + + @override + String failedToSaveMetadata(Object e) { + return 'Failed to save metadata: $e'; + } + + @override + String get failedToSaveMetadata2 => 'Failed to save metadata.'; + + @override + String get failedToStartStreaming => 'Failed to start streaming'; + + @override + String get failedToStopStreaming => 'Failed to stop streaming'; + + @override + String get faintHueShiftFromAlbumArt => 'Faint hue shift from album art.'; + + @override + String get fallback => 'Fallback'; + + @override + String get fallbackAudio => 'Fallback Audio'; + + @override + String get fallbackAudioActivated => 'Fallback audio activated'; + + @override + String get fallbackAudioDeactivated => 'Fallback audio deactivated'; + + @override + String get fallbackAudioWillBeUsedIf => + 'Fallback audio will be used if UAC2 device fails'; + + @override + String get fastDirectTrackingImmediateResponse => + 'Fast direct tracking — immediate response'; + + @override + String get fastIndexScrolling => 'Fast Index Scrolling'; + + @override + String get favoriteAll => 'Favorite all'; + + @override + String get favoriteRemoval => 'Favorite Removal'; + + @override + String get favoriteSongs => 'Favorite Songs'; + + @override + String get favorites => 'Favorites'; + + @override + String get favoritesYouHaveNotRevisitedLately => + 'Favorites you have not revisited lately'; + + @override + String get feb => 'Feb'; + + @override + String get feedback => 'Feedback'; + + @override + String get file => 'File'; + + @override + String get fileInformation => 'File Information'; + + @override + String get filePath => 'File Path'; + + @override + String files(Object done, Object total) { + return '$done / $total files'; + } + + @override + String files2(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count files', + one: '$count file', + ); + return '$_temp0'; + } + + @override + String filesChecked(Object arg1) { + return '$arg1 files checked…'; + } + + @override + String get filter => 'Filter'; + + @override + String get filterByFormat => 'FILTER BY FORMAT'; + + @override + String get filterFilesSizeLimitsAndPlaylist => + 'Filter files, size limits, and playlist import options'; + + @override + String get filterLogs => 'Filter logs…'; + + @override + String get filterNonMusicFilesFolders => 'Filter Non-Music Files & Folders'; + + @override + String get findAndCleanUpDuplicateSongs => + 'Find and clean up duplicate songs'; + + @override + String get findAndRemoveDuplicateSongs => 'Find and remove duplicate songs'; + + @override + String get findSongsArtistsAlbumsFolders => + 'Find songs, artists, albums, folders…'; + + @override + String get fineTuneTheOverallGain => 'Fine-tune the overall gain'; + + @override + String get finishingMetadataEnrichment => 'Finishing metadata enrichment…'; + + @override + String finishingMetadataForSongs(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'Finishing metadata for $count songs…', + one: 'Finishing metadata for $count song…', + ); + return '$_temp0'; + } + + @override + String get finishingUp => 'Finishing up…'; + + @override + String get fix => 'Fix'; + + @override + String get fixMissingMetadata => 'Fix Missing Metadata'; + + @override + String get fixedBands => '31 fixed bands'; + + @override + String fixedCenterFrequenciesWithADb(Object arg1) { + return 'Fixed center frequencies with a $arg1 dB range. Tap to interact.'; + } + + @override + String get flac24Bit96Khz => 'FLAC · 24-bit / 96 kHz'; + + @override + String get flat => 'Flat'; + + @override + String get flatResponse => 'Flat response'; + + @override + String get flick => 'Flick'; + + @override + String get flickCanAttemptToPreferA => + 'Flick can attempt to prefer a specific codec above, but success depends on your device, headset, and Android version. Codec forcing uses a hidden system API and may not work on non-rooted devices.'; + + @override + String get flickCanReceivePlaybackHandoffsFrom => + 'Flick can receive playback handoffs from Locker (another Moss app). Playback intents contain only song file paths/metadata. No personal data is exchanged. The integration is entirely local.'; + + @override + String get flickChecksFlickPlayerSiteFor => + 'Flick checks flick-player.site for updates whenever you are online'; + + @override + String get flickIsBuiltAndMaintainedBy => + 'Flick is built and maintained by one person with zero budget. No team, no funding, no ads.'; + + @override + String get flickLogs => 'Flick logs'; + + @override + String get flickPlayer => 'Flick Player'; + + @override + String get flickPlayerDoesNotCollectStore => + 'Flick Player does not collect, store, or transmit any personal data. No personal information, usage analytics, crash reports, or advertising identifiers are gathered. No data is shared with third parties.'; + + @override + String get flickPreview => 'Flick Preview'; + + @override + String get flickReplay => 'Flick Replay'; + + @override + String get flickScansForPlayStoreUpdates => + 'Flick scans for Play Store updates whenever you are online'; + + @override + String get flickWillAlwaysBeFreeDonations => + 'Flick will always be free. Donations keep the project alive without paywalls or subscriptions.'; + + @override + String get flickWillForceYourChosenCodec => + 'Flick will force your chosen codec on connect'; + + @override + String get flickplayer => 'FlickPlayer'; + + @override + String get floatingIsland => 'Floating Island'; + + @override + String get floatingMiniPlayer => 'Floating Mini-Player'; + + @override + String get folder => 'Folder'; + + @override + String get folderLimit => 'FOLDER LIMIT'; + + @override + String get folderName => 'Folder Name'; + + @override + String folderOf(Object current, Object total) { + return 'Folder $current of $total'; + } + + @override + String folderOf2(Object current, Object total) { + return 'Folder $current of $total'; + } + + @override + String get folderSongCount => 'Folder Song Count'; + + @override + String get folders => 'Folders'; + + @override + String folders2(Object arg1) { + return '$arg1 folders'; + } + + @override + String get foldersScanningAndDuplicates => + 'Folders, scanning, and duplicates'; + + @override + String get foldersShownPerPage => 'Folders shown per page'; + + @override + String get fontScale => 'Font Scale'; + + @override + String get footerLine => 'Footer line'; + + @override + String get forceDop => 'Force DoP'; + + @override + String get forceDopAlwaysUseDsdOver => + 'Force DoP — Always use DSD over PCM (USB DAC)'; + + @override + String get forcePcm => 'Force PCM'; + + @override + String get forcePcmAlwaysConvertDsdTo => + 'Force PCM — Always convert DSD to PCM'; + + @override + String get format => 'Format'; + + @override + String get formatControlsAreDisabledTheEngine => + 'Format controls are disabled. The engine uses its default format.'; + + @override + String get formatStrategy => 'Format Strategy'; + + @override + String get formatStrategyAndCustomFormatControls => + 'Format strategy and custom format controls are active.'; + + @override + String get formatStrategyIsDisabledInBit => + 'Format strategy is disabled in Bit-perfect (USB DAC) mode because exact sample rate matching is required. Disable Bit-perfect (USB DAC) to change format preferences.'; + + @override + String get formatStrategyIsUnavailableBecauseAudio => + 'Format strategy is unavailable because Audio Format is disabled in Settings.'; + + @override + String foundOnline(Object arg1) { + return 'Found \"$arg1\" online.'; + } + + @override + String frPkt(Object arg1) { + return '$arg1 fr/pkt'; + } + + @override + String get freeOpenSource => 'Free & Open Source'; + + @override + String get freq => 'Freq'; + + @override + String get frequency => 'Frequency'; + + @override + String get frequencyFocus => 'Frequency Focus'; + + @override + String get freshAdditions => 'Fresh Additions'; + + @override + String from(Object sourceLabel) { + return 'From $sourceLabel'; + } + + @override + String get fromSquareCornersToARounded => + 'From square corners to a rounded bar'; + + @override + String get fullBleedAlbumArtWithThe => + 'Full-bleed album art with the current cinematic look.'; + + @override + String get fullLibrary => 'Full Library'; + + @override + String get fullLibraryAccess => 'Full Library Access'; + + @override + String get fullPlayer => 'Full Player'; + + @override + String get fullScan => 'Full scan'; + + @override + String get fullSpectrum => 'Full Spectrum'; + + @override + String get fullViewCardSize => 'Full-view card size'; + + @override + String get fullViewCardSize2 => 'Full-view Card Size'; + + @override + String get fullscreen => 'Fullscreen'; + + @override + String get fundingNativeDsdDsfPlaybackDevelopment => + 'Funding native DSD/DSF playback development — a highly requested feature for audiophiles.'; + + @override + String get fxOff => 'FX off'; + + @override + String get fxOn => 'FX on'; + + @override + String get gain => 'Gain'; + + @override + String get gallery => 'Gallery'; + + @override + String get gapAboveNavigation => 'Gap Above Navigation'; + + @override + String get gaplessPlayback => 'Gapless Playback'; + + @override + String get gaplessViewModeAndAppearance => + 'Gapless, view mode, and appearance'; + + @override + String gb(Object arg1) { + return '$arg1 GB'; + } + + @override + String get generatedFromYourListeningHabitsFavorites => + 'Generated from your listening habits, favorites, and newest additions.'; + + @override + String get genre => 'Genre'; + + @override + String get geometry => 'Geometry'; + + @override + String get getStarted => 'Get Started'; + + @override + String get getTheLatestApkFromFlick => + 'Get the latest APK from flick-player.site'; + + @override + String get getYourApiCredentials => 'Get your API credentials'; + + @override + String get github => 'GitHub'; + + @override + String get goToAlbum => 'Go to Album'; + + @override + String get goToArtist => 'Go to Artist'; + + @override + String get goodAfternoon => 'Good afternoon'; + + @override + String get goodEvening => 'Good evening'; + + @override + String get goodMorning => 'Good morning'; + + @override + String get gotIt => 'Got it'; + + @override + String get grantBluetoothAccess => 'Grant Bluetooth access'; + + @override + String get grantedScansReadEveryVolumeDirectly => + 'Granted — scans read every volume directly, including DSD/DSF/WavPack'; + + @override + String get graphic => 'Graphic'; + + @override + String get graphicEq => 'Graphic EQ'; + + @override + String get green => 'Green'; + + @override + String get groupingByTitleArtistThisIs => + 'Grouping by title & artist — this is usually quick.'; + + @override + String get groups => 'Groups'; + + @override + String groupsToRemove(Object arg1, Object arg2) { + return '$arg1 groups • $arg2 to remove'; + } + + @override + String groupsToRemove2(Object arg1, Object toRemove) { + return '$arg1 groups • $toRemove to remove'; + } + + @override + String get growsFurtherIfLargerSystemText => + 'Grows further if larger system text needs room'; + + @override + String hAgo(Object arg1) { + return '${arg1}h ago'; + } + + @override + String get hapticFeedback => 'Haptic Feedback'; + + @override + String get hardwareUsbDac => 'Hardware (USB DAC)'; + + @override + String get hardwareVolumeIsDetectedButWrites => + 'Hardware volume is detected, but writes stay blocked while live direct USB playback is active.'; + + @override + String get hasArtwork => 'Has artwork'; + + @override + String get havingMoreThan4ButtonsMay => + 'Having more than 4 buttons may cause text labels to compress. Consider reducing the button spacing below.'; + + @override + String get heavyRotation => 'Heavy Rotation'; + + @override + String get held => 'Held'; + + @override + String get help => 'Help'; + + @override + String get helpManual => 'Help & Manual'; + + @override + String get hiResDirect => 'Hi-Res Direct'; + + @override + String get hidden => 'Hidden'; + + @override + String get hideLyrics => 'Hide lyrics'; + + @override + String get hideNavigationButtonsAfterBeingIdle => + 'Hide navigation buttons after being idle'; + + @override + String get hidePassword => 'Hide password'; + + @override + String get hideShortStingersRingtonesAndVoice => + 'Hide short stingers, ringtones, and voice fragments'; + + @override + String get hideTheFloatingMiniPlayerPill => + 'Hide the floating mini-player pill'; + + @override + String get hideTheIndexRailAfterInactivity => + 'Hide the index rail after inactivity'; + + @override + String get hideVisualizer => 'Hide visualizer'; + + @override + String get hideVisualizer2 => 'Hide Visualizer'; + + @override + String get high => 'High'; + + @override + String get high120hz => 'High (120Hz)'; + + @override + String get highFrequenciesOnly => 'High frequencies only'; + + @override + String get highPass => 'High Pass'; + + @override + String get highQuality => 'High Quality'; + + @override + String get highQualityEngine => 'High Quality Engine'; + + @override + String get highQualityWidelySupported => 'High quality, widely supported'; + + @override + String get highResolutionAptx => 'High-resolution aptX'; + + @override + String get highShelf => 'High Shelf'; + + @override + String get highestBitrateUpTo990Kbps => 'Highest bitrate (up to 990 kbps)'; + + @override + String get highestQuality => 'Highest Quality'; + + @override + String get historyCleared => 'History cleared'; + + @override + String get holdASongToUnfavorite => 'Hold a song to unfavorite'; + + @override + String get homeScreenSections => 'Home Screen Sections'; + + @override + String get horizontalReach => 'Horizontal Reach'; + + @override + String hourUnit(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'hours', + one: 'hour', + ); + return '$_temp0'; + } + + @override + String get howFarTheArcOpensFrom => + 'How far the arc opens from the left edge'; + + @override + String get howMuchSideCardsShrinkAway => + 'How much side cards shrink away from center'; + + @override + String get howWeHandleYourData => 'How we handle your data'; + + @override + String get howWideEachCardSpansAcross => + 'How wide each card spans across the screen'; + + @override + String get httpBasicNeedsItRecoverableStored => + 'HTTP Basic needs it recoverable; stored encoded'; + + @override + String hz(Object rate) { + return '$rate Hz'; + } + + @override + String hz3(Object hz) { + return '$hz Hz'; + } + + @override + String get hz5 => 'Hz'; + + @override + String hz6(Object arg1) { + return '$arg1 Hz'; + } + + @override + String get hzTuning => '432 Hz Tuning'; + + @override + String get iconSize => 'Icon Size'; + + @override + String identified(int count, Object note) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return 'Identified $_temp0$note.'; + } + + @override + String get identifyAlbum => 'Identify album'; + + @override + String get identifyAlbum2 => 'Identify Album'; + + @override + String get identifyAlbumsWithUnknownArtistOr => + 'Identify albums with unknown artist or title tags'; + + @override + String get idle => 'Idle'; + + @override + String get ifYouConnectYourLastFm => + 'If you connect your Last.fm account, credentials are stored securely on-device. Play data is sent only to Last.fm. We do not receive or process this data.'; + + @override + String get ignoreTracksUnder500Kb => 'Ignore Tracks Under 500 KB'; + + @override + String get ignoreTracksUnder60Seconds => 'Ignore Tracks Under 60 Seconds'; + + @override + String get immersive => 'Immersive'; + + @override + String get immersiveFullViewTimer => 'Immersive Full View Timer'; + + @override + String importFailed(Object e) { + return 'Import failed: $e'; + } + + @override + String get importM3uM3u8 => 'Import M3U/M3U8'; + + @override + String get importM3uM3u8Playlists => 'Import M3U/M3U8 Playlists'; + + @override + String get importPresetFile => 'Import preset file'; + + @override + String imported(Object arg1) { + return 'Imported \"$arg1\"'; + } + + @override + String get importedArtIsSavedInsideThe => + 'Imported art is saved inside the app and synced to every song in this album.'; + + @override + String get importedArtIsSavedInsideThe2 => + 'Imported art is saved inside the app for this song only.'; + + @override + String importedWithSongs(Object arg1, Object arg2, Object unmatchedText) { + return 'Imported \"$arg1\" with $arg2 songs.$unmatchedText'; + } + + @override + String get impulseResponse => 'Impulse response'; + + @override + String get inAppUpdates => 'In-App Updates'; + + @override + String inLabel(Object folder) { + return 'in $folder'; + } + + @override + String inYourLibrary(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return '$_temp0 in your library'; + } + + @override + String get inactive => 'Inactive'; + + @override + String get incredibleOverAMonthOfDaily => + 'Incredible — over a month of daily listening.'; + + @override + String get info2 => 'Info'; + + @override + String get initializing => 'Initializing…'; + + @override + String get inputGain => 'Input Gain'; + + @override + String get inst => 'Inst'; + + @override + String get instructions => 'Instructions'; + + @override + String get instrumental => 'Instrumental'; + + @override + String get integrations => 'Integrations'; + + @override + String get interactiveEq => 'Interactive EQ'; + + @override + String get interactiveTutorial => 'Interactive Tutorial'; + + @override + String get interfaceClaimed => 'Interface claimed'; + + @override + String get interfaceLabel => 'Interface'; + + @override + String isOfflineRetainedSongsStillListed(Object folder) { + return '$folder is offline — retained songs still listed'; + } + + @override + String get isochronousUsb => 'Isochronous USB'; + + @override + String get itemSpacing => 'Item Spacing'; + + @override + String items(Object count) { + return '$count items'; + } + + @override + String get jan => 'Jan'; + + @override + String get jellyfin => 'Jellyfin'; + + @override + String get jellyfinEmby => 'Jellyfin · Emby'; + + @override + String get jul => 'Jul'; + + @override + String get jumpBackIn => 'Jump Back In'; + + @override + String get jumpToTheFlickListingAnd => + 'Jump to the Flick listing and update from there'; + + @override + String get jun => 'Jun'; + + @override + String get justAudioExoplayer => 'just_audio / ExoPlayer'; + + @override + String get justAudioExoplayerDefault => 'just_audio / ExoPlayer (default)'; + + @override + String get justNow => 'Just now'; + + @override + String get karaokeEffect => 'Karaoke effect'; + + @override + String get karaokePreview => 'Karaoke Preview'; + + @override + String kb(Object arg1) { + return '$arg1 KB'; + } + + @override + String get keepAll => 'Keep all'; + + @override + String get keepEditing => 'Keep Editing'; + + @override + String get keepItGoingOpenTomorrowTo => + 'Keep it going. Open tomorrow to add another day.'; + + @override + String get keepListeningWithFlick => 'Keep listening with Flick'; + + @override + String get keepMiniPlayerAndNavVisible => 'Keep mini player and nav visible'; + + @override + String get keepPlaybackPausedWhenADevice => + 'Keep playback paused when a device reconnects'; + + @override + String get keepPlayingOnQuit => 'Keep Playing on Quit'; + + @override + String get keepRelativeLevelsInsideEachAlbum => + 'Keep relative levels inside each album'; + + @override + String get keepTheSessionMovingOrHead => + 'Keep the session moving or head straight back to the player.'; + + @override + String get keepYourReplay => 'Keep your Replay.'; + + @override + String keeping(Object type, Object br) { + return 'Keeping • $type • $br'; + } + + @override + String keepingOfToRemove(Object keptCount, Object arg1, Object removeCount) { + return 'Keeping $keptCount of $arg1 • $removeCount to remove'; + } + + @override + String get keepingThisVersion => 'Keeping this version'; + + @override + String get keepsBitPerfectAudioAliveIn => + 'Keeps bit-perfect audio alive in the background'; + + @override + String get keepsSoftwareVolumeAndDspActive => + 'Keeps software volume and DSP active on the DAP shared path.'; + + @override + String get keptInSecureStorageToRe => + 'Kept in secure storage to re-sign in when the token expires'; + + @override + String keptWillBeRemoved(Object keptCount, Object removeCount) { + return '$keptCount kept • $removeCount will be removed'; + } + + @override + String khz(Object arg1) { + return '${arg1}kHz'; + } + + @override + String khz2(Object arg1) { + return '$arg1 kHz'; + } + + @override + String khzBit(Object arg1, Object arg2) { + return '${arg1}kHz/${arg2}bit'; + } + + @override + String khzBit2(Object arg1, Object arg2) { + return '${arg1}kHz/${arg2}bit'; + } + + @override + String khzBitCh(Object arg1, Object arg2, Object arg3) { + return '${arg1}kHz / ${arg2}bit / ${arg3}ch'; + } + + @override + String get koFi => 'Ko-fi'; + + @override + String get label => 'Label'; + + @override + String get labelOrganization => 'Label / Organization'; + + @override + String get language => 'Language'; + + @override + String get languageSectionDescription => + 'Choose the language used across the app.'; + + @override + String get languageSystemDefault => 'System default'; + + @override + String get lastFm => 'Last.fm'; + + @override + String get lastFmConfiguration => 'Last.fm Configuration'; + + @override + String get lastFmConnected => 'Last.fm Connected'; + + @override + String get lastFmConnected2 => 'Last.fm connected!'; + + @override + String get lastFmListenbrainzScrobbling => + 'Last.fm & ListenBrainz scrobbling'; + + @override + String get lastFmScrobbling => 'Last.fm Scrobbling'; + + @override + String get lastPick => 'Last pick'; + + @override + String get lastUpdated => 'Last Updated'; + + @override + String get lastWeek => 'Last Week'; + + @override + String get lateNightSessions => 'Late Night Sessions'; + + @override + String get latestArrivalsFromYourLibrary => + 'Latest arrivals from your library'; + + @override + String get latestUpdate => 'Latest Update'; + + @override + String get layered => 'Layered'; + + @override + String get layoutMode => 'Layout Mode'; + + @override + String get layoutModeSizingAndQuickActions => + 'Layout mode, sizing, and quick actions'; + + @override + String get ldac330Kbps => 'LDAC 330 kbps'; + + @override + String get ldac660Kbps => 'LDAC 660 kbps'; + + @override + String get ldac990Kbps => 'LDAC 990 kbps'; + + @override + String get ldacAdaptive => 'LDAC Adaptive'; + + @override + String get ldacBitsPerSample => 'LDAC bits per sample'; + + @override + String get leLsbLittleEndianSubslotLsb => + 'LE-LSB — little-endian subslot, LSB first'; + + @override + String get leMsbLittleEndianSubslotMsb => + 'LE-MSB — little-endian subslot, MSB first'; + + @override + String get leaveEmptyToKeepTheCurrent => + 'Leave empty to keep the current credentials'; + + @override + String get left => 'Left'; + + @override + String get leftBottom => 'Left (bottom)'; + + @override + String get leftBottomButton => 'Left (Bottom) Button'; + + @override + String get leftTop => 'Left (top)'; + + @override + String get leftTopButton => 'Left (Top) Button'; + + @override + String get length => 'Length:'; + + @override + String get lengthOfTheOverlap => 'Length of the overlap'; + + @override + String lengthS(Object arg1) { + return 'Length ${arg1}s'; + } + + @override + String get letAndroidChooseTheBestCodec => + 'Let Android choose the best codec'; + + @override + String get letAndroidChooseTheOutputDevice => + 'Let Android choose the output device'; + + @override + String get letAndroidNegotiateTheCodecAutomatically => + 'Let Android negotiate the codec automatically'; + + @override + String get letOboePickTheBestApi => + 'Let Oboe pick the best API. AAudio first, then OpenSL ES fallback.'; + + @override + String get letSTakeAQuickTour => + 'Let\'s take a quick tour of your new music player.'; + + @override + String get letTheSystemDecideBestBattery => + 'Let the system decide — best battery life'; + + @override + String get letsFlickScanYourEntireLibrary => + 'Lets Flick scan your entire library directly, including DSD/DSF/WavPack files some devices hide from the system media index'; + + @override + String get level => 'Level'; + + @override + String get libraryEmptied => 'Library emptied'; + + @override + String get libraryGlanceCard => 'Library Glance Card'; + + @override + String get libraryLabel => 'Library'; + + @override + String get licenses => 'Licenses'; + + @override + String get light => 'Light'; + + @override + String likedSongs(Object arg1) { + return '$arg1 liked songs'; + } + + @override + String get likedSongsLiveHere => 'Liked songs live here'; + + @override + String get likesAndReplaysBlendedTogether => + 'Likes and replays blended together'; + + @override + String get limit => 'Limit'; + + @override + String get limitPositiveGainSoTheLevel => + 'Limit positive gain so the level never exceeds full scale'; + + @override + String get limiter => 'Limiter'; + + @override + String get limiterOff => 'Limiter off'; + + @override + String get limiterOn => 'Limiter on'; + + @override + String get line => 'Line'; + + @override + String lineOf(Object arg1, Object arg2) { + return 'Line $arg1 of $arg2'; + } + + @override + String lineOfWords( + Object arg1, + Object arg2, + Object captured, + Object segmentCount, + ) { + return 'Line $arg1 of $arg2 · $captured/$segmentCount words'; + } + + @override + String get linear => 'Linear'; + + @override + String get lines => 'Lines'; + + @override + String lines2(Object arg1) { + return '$arg1 lines'; + } + + @override + String get linkReady => 'Link ready'; + + @override + String linkedToThisSong(Object arg1) { + return 'Linked \"$arg1\" to this song.'; + } + + @override + String get list => 'List'; + + @override + String get listAvailableLocalAudioOutputDevices => + 'List available local audio output devices'; + + @override + String get listenbrainz => 'ListenBrainz'; + + @override + String get listenbrainzConnected => 'ListenBrainz Connected'; + + @override + String get listenbrainzConnected2 => 'ListenBrainz connected!'; + + @override + String get listeningHours => 'Listening Hours'; + + @override + String listeningToByOnFlick(Object arg1, Object arg2) { + return 'Listening to $arg1 by $arg2 on Flick'; + } + + @override + String get littleEndianSubslotLsbFirstBits => + 'Little-endian subslot, LSB-first bits'; + + @override + String get littleEndianSubslotMsbFirstBits => + 'Little-endian subslot, MSB-first bits'; + + @override + String get livePreview => 'Live Preview'; + + @override + String get livingOrnament => 'Living ornament'; + + @override + String get loadAJsonOrTxtPreset => 'Load a JSON or TXT preset'; + + @override + String get loadAnImpulseResponseForRoom => + 'Load an impulse response for room reverb, crossfeed, cabinet, or correction.'; + + @override + String get loadIr => 'Load IR'; + + @override + String loadedIr(Object displayName) { + return 'Loaded IR: $displayName'; + } + + @override + String get loadingArtwork => 'Loading artwork'; + + @override + String get loadingArtwork2 => 'Loading artwork…'; + + @override + String get loadingFavoritesRecentSessionsGenerated => + 'Loading favorites, recent sessions, generated mixes, and playlists.'; + + @override + String get loadingPatchNotes => 'Loading patch notes...'; + + @override + String get loadingReplay => 'Loading Replay'; + + @override + String get loadingSession => 'Loading session...'; + + @override + String get localData => 'Local Data'; + + @override + String get locked => 'Locked'; + + @override + String get logFrequencyControl => 'Log-frequency control'; + + @override + String get logs => 'Logs'; + + @override + String get logsCopied => 'Logs copied'; + + @override + String get longPress => 'Long Press'; + + @override + String get longSongTitles => 'Long Song Titles'; + + @override + String get look => 'Look'; + + @override + String get lookingForCoverArtFromMusicbrainz => + 'Looking for cover art from MusicBrainz and Cover Art Archive.'; + + @override + String get lookingForTheLatestFlickRelease => + 'Looking for the latest Flick release right now'; + + @override + String get lookingForTheLatestPlayStore => + 'Looking for the latest Play Store update right now'; + + @override + String get lossless => ' Lossless'; + + @override + String get losslessQualityPreservedDuringConversion => + 'Lossless quality preserved during conversion'; + + @override + String get low => 'Low'; + + @override + String get lowAndHighFrequenciesScoopedMids => + 'Low and high frequencies, scooped mids'; + + @override + String get lowFrequenciesOnly => 'Low frequencies only'; + + @override + String get lowLatencyGoodQuality => 'Low latency, good quality'; + + @override + String get lowLatencyMode => 'Low-latency Mode'; + + @override + String get lowPass => 'Low Pass'; + + @override + String get lowShelf => 'Low Shelf'; + + @override + String get lrclib => 'LRCLib'; + + @override + String get lyric => 'Lyric'; + + @override + String get lyrics => 'Lyrics'; + + @override + String get lyricsPreview => 'Lyrics Preview'; + + @override + String get lyricsSavedFromLrclib => 'Lyrics saved from LRCLib.'; + + @override + String get lyricsSavingBehavior => 'Lyrics saving behavior'; + + @override + String get lyricsSyncHelp => 'Lyrics Sync Help'; + + @override + String get lyricsSyncStudio => 'Lyrics Sync Studio'; + + @override + String get lyricsText => 'Lyrics Text'; + + @override + String m(Object arg1) { + return '${arg1}m'; + } + + @override + String m2(Object arg1) { + return '${arg1}m'; + } + + @override + String mAgo(Object arg1) { + return '${arg1}m ago'; + } + + @override + String get madeForYou => 'Made For You'; + + @override + String get makeup => 'Makeup'; + + @override + String get manual => 'Manual'; + + @override + String get manualOrder => 'Manual Order'; + + @override + String get manualQueue => 'Manual queue'; + + @override + String get manufacturer => 'Manufacturer'; + + @override + String get mar => 'Mar'; + + @override + String get masterBypassed => 'Master bypassed'; + + @override + String get matchAudioFilename => 'Match Audio Filename'; + + @override + String matchByArtistAlbumAndTrack(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count files', + one: '$count file', + ); + return 'Match $_temp0 by artist, album and track length'; + } + + @override + String get matchEqToYourHeadphoneModel => 'Match EQ to your headphone model'; + + @override + String get matchNavigation => 'Match navigation'; + + @override + String get matches => 'Matches'; + + @override + String maxB(Object arg1) { + return 'Max $arg1 B'; + } + + @override + String get maximumAudioQuality => 'Maximum audio quality'; + + @override + String get maximumSmoothnessUsesMoreBattery => + 'Maximum smoothness — uses more battery'; + + @override + String get may => 'May'; + + @override + String get may42026 => 'May 4, 2026'; + + @override + String get mayStopInTheBackgroundOn => + 'May stop in the background on some devices'; + + @override + String mb(Object arg1) { + return '$arg1 MB'; + } + + @override + String get media => 'Media'; + + @override + String get medium => 'Medium'; + + @override + String get menu => 'Menu'; + + @override + String get metadata => 'Metadata'; + + @override + String get metropolitan => 'Metropolitan'; + + @override + String mhz(Object arg1) { + return '$arg1 MHz'; + } + + @override + String get mid => 'Mid'; + + @override + String get midFrequenciesOnly => 'Mid frequencies only'; + + @override + String get midnightCityDreams => 'Midnight City Dreams'; + + @override + String get midnightSignal => 'Midnight Signal'; + + @override + String get milestone => 'Milestone'; + + @override + String get milestones => 'Milestones'; + + @override + String min(Object arg1) { + return '$arg1 min'; + } + + @override + String get miniPlayer => 'Mini Player'; + + @override + String get miniPlayerAppearance => 'Mini Player Appearance'; + + @override + String get miniPlayerDefaultsRestored => 'Mini player defaults restored'; + + @override + String get miniPlayerHeight => 'Mini Player Height'; + + @override + String get miniPlayerLayout => 'Mini Player Layout'; + + @override + String get minimal => 'Minimal'; + + @override + String get minimize => 'Minimize'; + + @override + String get minimserverServiioKodi => 'MinimServer · Serviio · Kodi'; + + @override + String get mirrorTest => 'Mirror Test'; + + @override + String get mirrored => 'Mirrored'; + + @override + String get mitLicenseCopyrightC2026Flick => + '\nMIT License\n\nCopyright (c) 2026 Flick Player Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n'; + + @override + String get mix => 'Mix'; + + @override + String mix2(Object arg1) { + return 'Mix $arg1'; + } + + @override + String get mixer => 'Mixer'; + + @override + String get mixerManagement => 'Mixer Management'; + + @override + String moAgo(Object arg1) { + return '${arg1}mo ago'; + } + + @override + String get mod => 'Mod'; + + @override + String get moderate => 'Moderate'; + + @override + String get mono => 'Mono'; + + @override + String get monthly => 'Monthly'; + + @override + String get more => 'More'; + + @override + String more2(Object arg1, Object arg2) { + return '$arg1 + $arg2 more'; + } + + @override + String get moreActions => 'More actions'; + + @override + String get moreArtists => 'More artists'; + + @override + String get moreArtists2 => 'More Artists'; + + @override + String get moreExportOptions => 'More export options'; + + @override + String moreFrom(Object arg1) { + return 'More from $arg1'; + } + + @override + String get moreFromArtist => 'More from artist'; + + @override + String get moreFromArtist2 => 'More from Artist'; + + @override + String moreTo(Object arg1, Object arg2) { + return '$arg1 more to $arg2'; + } + + @override + String moreToUnlock(Object remaining, Object unit) { + return '$remaining more $unit to unlock.'; + } + + @override + String get mossEcosystem => 'Moss Ecosystem'; + + @override + String get mostDlnaServersNeedNoPassword => + 'Most DLNA servers need no password'; + + @override + String get mostPlayed => 'Most Played'; + + @override + String mostReplayed(Object arg1) { + return 'Most replayed · $arg1'; + } + + @override + String get motionArtInBitPerfect => 'Motion Art in Bit-Perfect'; + + @override + String get motionArtIsReplacedWhileBit => + 'Motion art is replaced while bit-perfect output is active'; + + @override + String get motionArtPlaysDuringBitPerfect => + 'Motion art plays during bit-perfect audio (may interrupt playback on some DAPs)'; + + @override + String get motionArtRefreshed => 'Motion art refreshed'; + + @override + String get moveEveryStampedLyricForwardOr => + 'Move every stamped lyric forward or backward together.'; + + @override + String get movement => 'Movement'; + + @override + String ms(Object arg1) { + return '$arg1 ms'; + } + + @override + String ms2(Object arg1) { + return '$arg1 ms'; + } + + @override + String ms3(Object arg1) { + return '$arg1 ms'; + } + + @override + String ms4(Object arg1) { + return '$arg1 ms'; + } + + @override + String ms5(Object arg1) { + return '$arg1 ms'; + } + + @override + String get multiFilterBands => 'Multi-filter bands'; + + @override + String musicFolders(Object arg1) { + return '$arg1 music folders'; + } + + @override + String get mute => 'Mute'; + + @override + String my(Object arg1) { + return 'My $arg1'; + } + + @override + String nDb(Object arg1, Object arg2) { + return '$arg1%\n$arg2 dB'; + } + + @override + String get nameAZ => 'Name (A-Z)'; + + @override + String narrow(Object amount) { + return '$amount% narrow'; + } + + @override + String get nativeDsd => 'Native DSD'; + + @override + String get nativeDsdExperimental => 'Native DSD (Experimental)'; + + @override + String get nativeDsdExperimentalMayBeBuggy => + 'Native DSD — Experimental (may be buggy)'; + + @override + String get nativeFlickPresetFormat => 'Native Flick preset format'; + + @override + String get naturalEqualizerFeelResponsiveYetSmooth => + 'Natural equalizer feel — responsive yet smooth'; + + @override + String get natureAmbient => 'Nature Ambient'; + + @override + String get navidromeAirsonicGonic => 'Navidrome · Airsonic · Gonic'; + + @override + String get navigationAppearance => 'Navigation Appearance'; + + @override + String get navigationBar => 'Navigation Bar'; + + @override + String get navigationDefaultsRestored => 'Navigation defaults restored'; + + @override + String get needsMetadata => 'Needs metadata'; + + @override + String negotiated(Object arg1) { + return 'Negotiated: $arg1'; + } + + @override + String get neonNights => 'Neon Nights'; + + @override + String get neonSkyline => 'Neon Skyline'; + + @override + String get network => 'Network'; + + @override + String get networkSources => 'Network Sources'; + + @override + String neutral(Object amount) { + return '$amount% neutral'; + } + + @override + String get neverSynced => 'Never synced'; + + @override + String get newLabel => 'New'; + + @override + String get next => 'Next'; + + @override + String get nextSong => 'Next song'; + + @override + String get nextSong2 => 'Next Song'; + + @override + String nextToGo(Object arg1, Object remaining, Object unit) { + return 'Next: $arg1 — $remaining $unit to go'; + } + + @override + String get nextcloudOwncloudSabredav => 'Nextcloud · ownCloud · SabreDAV'; + + @override + String get night => 'Night'; + + @override + String get no => 'No'; + + @override + String get noAchievementsYetKeepListening => + 'No achievements yet — keep listening'; + + @override + String get noAlbumDataYet => 'No album data yet'; + + @override + String get noAlbumsFound => 'No Albums Found'; + + @override + String get noAppleMusicReleaseFoundTry => + 'No Apple Music release found. Try editing the artist or album name and searching again.'; + + @override + String get noArtistsFound => 'No Artists Found'; + + @override + String noArtistsMatch(Object _searchQuery) { + return 'No artists match \"$_searchQuery\"'; + } + + @override + String get noAudioWasFoundIfThis => + 'No audio was found. If this folder contains music, a .nomedia file may be hiding it, or Android hasn\'t indexed it yet. Try enabling deep scan, or remove any .nomedia file and re-scan.'; + + @override + String get noCastingDevicesFoundMakeSure => + 'No casting devices found. Make sure your phone and the receiver are on the same network.'; + + @override + String get noCategoriesSelected => 'No categories selected'; + + @override + String get noChangelogNotesForThisVersion => + 'No changelog notes for this version yet.'; + + @override + String get noCustomPresetsYet => 'No custom presets yet.'; + + @override + String get noDuplicatesFound => 'No duplicates found'; + + @override + String get noFavoritesYet => 'No Favorites Yet'; + + @override + String get noFeaturedTrackYet => 'No featured track yet'; + + @override + String get noFoldersAdded => 'No Folders Added'; + + @override + String get noHistoryYet => 'No History Yet'; + + @override + String get noInternetConnectionPleaseCheckYour => + 'No internet connection. Please check your network and try again.'; + + @override + String get noLogsYet => 'No logs yet.'; + + @override + String get noLyricsFoundOnlineForThis => + 'No lyrics found online for this song.'; + + @override + String get noLyricsYet => 'No lyrics yet'; + + @override + String get noMatchFound => 'No match found'; + + @override + String get noMatches => 'No matches.'; + + @override + String noMatchesFor(Object _query) { + return 'No matches for \"$_query\"'; + } + + @override + String get noMatchesFound => 'No matches found'; + + @override + String get noMatchesTryFewerWordsOr => + 'No matches. Try fewer words or search online.'; + + @override + String get noMusicYet => 'No Music Yet'; + + @override + String get noNewAdditionsYet => 'No New Additions Yet'; + + @override + String get noNewUpdateFound => 'No new update found.'; + + @override + String get noOnlineArtworkFound => 'No online artwork found'; + + @override + String get noOutputDevicesAvailable => 'No output devices available.'; + + @override + String get noPatchNotesAvailableYet => 'No patch notes available yet.'; + + @override + String get noPlaybackYet => 'No playback yet'; + + @override + String get noPlaylistsYet => 'No playlists yet'; + + @override + String get noPlaylistsYet2 => 'No Playlists Yet'; + + @override + String get noPlaylistsYetNcreateOneIn => + 'No playlists yet.\nCreate one in the Playlists tab.'; + + @override + String get noRankingDataYet => 'No ranking data yet'; + + @override + String noResultsFor(Object query) { + return 'No results for \"$query\"'; + } + + @override + String noResultsFoundFor(Object query) { + return 'No results found for \"$query\".'; + } + + @override + String get noRipData => 'No rip data'; + + @override + String get noScanResultsYet => 'No scan results yet'; + + @override + String get noServerPlaylistsFound => 'No server playlists found'; + + @override + String get noServersConnected => 'No servers connected'; + + @override + String get noSongPlaying => 'No song playing'; + + @override + String get noSongsFound => 'No Songs Found'; + + @override + String get noSongsInThisPlaylist => 'No songs in this playlist'; + + @override + String get noUpcomingQueueItemsYet => 'No upcoming queue items yet.'; + + @override + String get noUpdateAvailable => 'No Update Available'; + + @override + String get noUrbData => 'No URB data'; + + @override + String get noUsbAudioDevicesFound => 'No USB audio devices found'; + + @override + String get noWordTimingYetAutoFill => + 'No word timing yet. Auto-fill spreads the words evenly as a starting point — or capture them in Word Sync mode.'; + + @override + String get none => 'None'; + + @override + String get normalizeEachTrackToMatchLoudness => + 'Normalize each track to match loudness'; + + @override + String get notAnAlacFile => 'Not an ALAC file'; + + @override + String get notAvailableInBitPerfectMode => + 'Not available in bit-perfect mode'; + + @override + String get notFoundOnlineTryADifferent => + 'Not found online. Try a different spelling.'; + + @override + String get notGrantedEnableSoScansCover => + 'Not granted — enable so scans cover DSD/DSF/WavPack files the system index may skip'; + + @override + String get notHeld => 'Not held'; + + @override + String get notRecommendedForNormalUsageDsd => + 'Not recommended for normal usage. DSD playback is unstable and may cause audio glitches.'; + + @override + String get notRegistered => 'Not registered'; + + @override + String get notSet => 'Not set'; + + @override + String get notStampedYet => 'Not stamped yet'; + + @override + String get notVerified => 'Not verified'; + + @override + String get notch => 'Notch'; + + @override + String get notchDepth => 'Notch Depth'; + + @override + String get noticeableTintingFromAlbumArt => + 'Noticeable tinting from album art.'; + + @override + String get nov => 'Nov'; + + @override + String get now => 'Now'; + + @override + String get nowPlaying => 'Now Playing'; + + @override + String get nowPlaying2 => 'Now playing'; + + @override + String get numberOnArt => 'Number on Art'; + + @override + String get oauthSignInNoPasswordStored => + 'OAuth sign-in; no password stored here'; + + @override + String get oceanWaves => 'Ocean Waves'; + + @override + String get oct => 'Oct'; + + @override + String get off => 'Off'; + + @override + String get offCropsToFillTheSquare => + 'Off crops to fill the square; on stretches the artwork edge-to-edge'; + + @override + String get offline => 'Offline'; + + @override + String get onAndroidTheStandardJustAudio => + 'On Android, the standard just_audio playback path now applies native counterparts for EQ, dynamics, balance, and spatial FX on supported devices. The Rust engine still delivers the most exact version of these controls, so some Android results are approximate.'; + + @override + String get onRepeat => 'On Repeat'; + + @override + String get onlineResults => 'Online Results'; + + @override + String get onlyLibraryEntriesAreRemovedYour => + 'Only library entries are removed — your audio files stay on disk.'; + + @override + String get onlyReReadFilesThatAre => + 'Only re-read files that are new or changed.'; + + @override + String get open => 'Open'; + + @override + String get openAndroidSettings => 'Open Android settings'; + + @override + String get openBluetoothCodecSettings => 'Open Bluetooth Codec Settings'; + + @override + String get openFullNotes => 'Open Full Notes'; + + @override + String get openInAppleMusic => 'Open in Apple Music'; + + @override + String get openInBrowser => 'Open in browser'; + + @override + String get openInPlayStore => 'Open in Play Store'; + + @override + String get openLibrary => 'Open Library'; + + @override + String get openListenbrainzOrgSettings => 'Open listenbrainz.org/settings'; + + @override + String get openManual => 'Open Manual'; + + @override + String get openPlayer => 'Open Player'; + + @override + String get openReleaseNotes => 'Open Release Notes'; + + @override + String get openSourceLicenses => 'Open source licenses'; + + @override + String get openThePlayStoreToInstall => + 'Open the Play Store to install the latest Flick build'; + + @override + String get openedFromLocker => 'Opened from Locker'; + + @override + String get openslEs => 'OpenSL ES'; + + @override + String get openslEsLegacy => 'OpenSL ES (legacy)'; + + @override + String get orRemoveAllUsingRecommendedPicks => + 'Or remove all using recommended picks'; + + @override + String get orbital => 'Orbital'; + + @override + String get orbitalSettingsReset => 'Orbital settings reset'; + + @override + String get otherPlaylists => 'Other Playlists'; + + @override + String get ourRustPoweredEngineCleanerSound => + 'Our Rust-powered engine. Cleaner sound and smoother playback — recommended for daily listening.'; + + @override + String get outlineTheMiniPlayer => 'Outline the mini player'; + + @override + String get output => 'Output'; + + @override + String get outputDevice => 'Output Device'; + + @override + String get outputMode => 'Output Mode'; + + @override + String get outputRate => 'Output rate'; + + @override + String get overlapTheEndOfATrack => + 'Overlap the end of a track with the next'; + + @override + String get overlayPermissionIsRequiredToShow => + 'Overlay permission is required to show the floating player'; + + @override + String get overviewMetricsChooseUpTo3 => 'Overview metrics · choose up to 3'; + + @override + String get paired => 'Paired'; + + @override + String get parametric => 'Parametric'; + + @override + String parametricBandsWithIndependentFrequency(Object arg1) { + return '$arg1 parametric bands with independent frequency, gain, and Q shaping. Tap to interact.'; + } + + @override + String get parametricEq => 'Parametric EQ'; + + @override + String get passthrough => 'Passthrough'; + + @override + String get password => 'Password'; + + @override + String get pasteOrTypeTheSongLyrics => + 'Paste or type the song lyrics here — one line per row'; + + @override + String get pasteYourListenbrainzToken => 'Paste your ListenBrainz token'; + + @override + String get patchNotes => 'Patch Notes'; + + @override + String get pause => 'Pause'; + + @override + String get pauseOnBluetoothConnect => 'Pause on Bluetooth Connect'; + + @override + String get pauseOnDisconnect => 'Pause on Disconnect'; + + @override + String get pauseOnUsbDacAttach => 'Pause on USB DAC Attach'; + + @override + String get pauseOnUsbDacDetach => 'Pause on USB DAC Detach'; + + @override + String get pcmFrames => 'PCM Frames'; + + @override + String get peakHour => 'Peak hour'; + + @override + String get peaking => 'Peaking'; + + @override + String get permission => 'Permission'; + + @override + String get personalPlaylist => 'Personal playlist'; + + @override + String get phoneAndHeadsetVolumeAreIndependent => + 'Phone and headset volume are independent'; + + @override + String get phoneAndHeadsetVolumeAreLinked => + 'Phone and headset volume are linked'; + + @override + String get photoFraming => 'Photo framing'; + + @override + String get pickALineWithLyrics => 'Pick a line with lyrics'; + + @override + String get pickALyricLineIn => + '1. Pick a lyric line in Lines, then switch to Tools.\n2. Press play and tap the big \"Tap Word\" button as you hear each word — the first tap also stamps the line.\n3. Tap a word chip to nudge, re-time, or clear it.\n4. Lines with every word stamped save with per-word karaoke timing.'; + + @override + String get pickAgain => 'Pick again'; + + @override + String get pickImage => 'Pick Image'; + + @override + String get pickUpExactlyWhereYourLast => + 'Pick up exactly where your last sessions left off.'; + + @override + String get pinchApartNarrowerHigherQNpinch => + 'Pinch apart = narrower (higher Q)\nPinch together = wider (lower Q)'; + + @override + String get pitch => 'Pitch'; + + @override + String pitchSemitones(int semitones) { + String _temp0 = intl.Intl.pluralLogic( + semitones, + locale: localeName, + other: '$semitones semitones', + one: '$semitones semitone', + ); + return '$_temp0'; + } + + @override + String get pixelatedLightestOnMemory => 'Pixelated — lightest on memory'; + + @override + String get plain => 'Plain'; + + @override + String get plainText => 'Plain Text'; + + @override + String get play => 'Play'; + + @override + String get playAFewSongsAndThis => + 'Play a few songs and this page will start filling with mixes, artists, and shortcuts.'; + + @override + String get playAFewTracksTodayTo => + 'Play a few tracks today to build your daily recap.'; + + @override + String get playARandomLibrarySongWhen => + 'Play a random library song when the queue ends'; + + @override + String get playAgain => 'Play Again'; + + @override + String get playAtTheRecordedLevel => 'Play at the recorded level'; + + @override + String get playBadges => 'Play badges'; + + @override + String get playCategoriesInRandomOrderTracks => + 'Play categories in random order, tracks in sequence'; + + @override + String get playInOrder => 'Play in order'; + + @override + String get playNext => 'Play next'; + + @override + String get playStoreUpdatesUseGooglePlay => + 'Play Store updates use Google Play In-App Update API (governed by Google\'s privacy policies). Patch notes are fetched from GitHub Releases API without sending personal data.'; + + @override + String get playback => 'Playback'; + + @override + String get playbackCacheLimit => 'Playback Cache Limit'; + + @override + String playbackCacheLimit2(Object arg1) { + return 'Playback cache limit: $arg1'; + } + + @override + String get playbackCacheUnlimited => 'Playback cache unlimited'; + + @override + String get playbackContinuesWhenABluetoothDevice => + 'Playback continues when a Bluetooth device connects'; + + @override + String get playbackContinuesWhenAUsbDac => + 'Playback continues when a USB DAC is plugged in'; + + @override + String get playbackContinuesWhenAUsbDac2 => + 'Playback continues when a USB DAC is unplugged'; + + @override + String get playbackContinuesWhenAudioOutput => + 'Playback continues when audio output disconnects'; + + @override + String get playbackContinuesWhenTheAppIs => + 'Playback continues when the app is swiped away'; + + @override + String get playbackDisplay => 'Playback & Display'; + + @override + String get playbackEngine => 'Playback Engine'; + + @override + String get playbackIsUsingAndroidManagedOutput => + 'Playback is using Android-managed output and may be resampled.'; + + @override + String get playbackIsUsingTheStandardAndroid => + 'Playback is using the standard Android output path.'; + + @override + String get playbackModeWillUpdateAfterThe => + 'Playback mode will update after the next route or playback refresh.'; + + @override + String get playbackPath => 'Playback Path'; + + @override + String get playbackPausesWhenABluetoothAudio => + 'Playback pauses when a Bluetooth audio device connects'; + + @override + String get playbackPausesWhenAUsbDac => + 'Playback pauses when a USB DAC is plugged in'; + + @override + String get playbackPausesWhenAUsbDac2 => + 'Playback pauses when a USB DAC is physically unplugged'; + + @override + String get playbackPausesWhenBluetoothOrHeadphones => + 'Playback pauses when Bluetooth or headphones disconnect'; + + @override + String get playbackPausesWhileNotificationSoundsPlay => + 'Playback pauses while notification sounds play'; + + @override + String get playbackResumesWhenADeviceReconnects => + 'Playback resumes when a device reconnects within 30 seconds'; + + @override + String get playbackSpeed => 'Playback Speed'; + + @override + String get playbackStopsWhenTheAppIs => + 'Playback stops when the app is swiped away'; + + @override + String played(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return '$_temp0 played'; + } + + @override + String get playerLayout => 'Player Layout'; + + @override + String playlist(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count playlists', + one: '$count playlist', + ); + return '$_temp0'; + } + + @override + String get playlist2 => 'Playlist'; + + @override + String playlistCreated(Object arg1) { + return 'Playlist \"$arg1\" created'; + } + + @override + String get playlistName => 'Playlist name'; + + @override + String get playlists => 'Playlists'; + + @override + String plays(Object arg1) { + return '$arg1 plays'; + } + + @override + String plays2(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count plays', + one: '1 play', + ); + return '$_temp0'; + } + + @override + String get playsInRotation => 'plays in rotation'; + + @override + String get pleaseEnterAPlaylistName => 'Please enter a playlist name'; + + @override + String get pleaseEnterYourListenbrainzUserToken => + 'Please enter your ListenBrainz user token.'; + + @override + String posterPreviewPlays(Object arg1, Object arg2) { + return '$arg1 poster preview. $arg2 plays.'; + } + + @override + String get preAmp => 'Pre-amp'; + + @override + String get preamp => 'Preamp'; + + @override + String get preferences => 'Preferences'; + + @override + String get preloadAudioData => 'Preload audio data'; + + @override + String get preloadLibraryAudio => 'Preload Library Audio'; + + @override + String get preloadingAudio => 'Preloading Audio'; + + @override + String preloadingAudio2(Object arg1, Object arg2) { + return 'Preloading audio $arg1/$arg2'; + } + + @override + String get preloadingAudio3 => 'Preloading audio'; + + @override + String get preparing => 'Preparing…'; + + @override + String get presence => 'Presence'; + + @override + String preset(Object activePresetName) { + return 'Preset: $activePresetName'; + } + + @override + String get presetImportedWithAdjustments => + 'Preset imported with adjustments'; + + @override + String get presetName => 'Preset name'; + + @override + String get presets => 'Presets'; + + @override + String get preventClipping => 'Prevent Clipping'; + + @override + String get preview => 'Preview'; + + @override + String get previewUse => 'Preview & Use'; + + @override + String get previousSong => 'Previous song'; + + @override + String get previousSong2 => 'Previous Song'; + + @override + String get prewarming => 'Prewarming'; + + @override + String get prioritiseConnectionStability => 'Prioritise connection stability'; + + @override + String get privacyPolicy => 'Privacy Policy'; + + @override + String get processingLive => 'Processing live'; + + @override + String get product => 'Product'; + + @override + String get productId => 'Product ID'; + + @override + String get progress => 'Progress'; + + @override + String get progressBar => 'Progress Bar'; + + @override + String get protocol => 'Protocol'; + + @override + String get pulledFromYourLateSessionPlays => + 'Pulled from your late-session plays'; + + @override + String get purple => 'Purple'; + + @override + String get queue => 'Queue'; + + @override + String queue2(Object count) { + return 'Queue $count'; + } + + @override + String get queueIsEmpty => 'Queue is empty'; + + @override + String queued(Object arg1) { + return 'Queued \"$arg1\"'; + } + + @override + String queuedSongs(Object arg1) { + return 'Queued $arg1 songs'; + } + + @override + String queuedSongs3(Object arg1) { + return 'Queued $arg1 songs'; + } + + @override + String get quickAccess => 'Quick Access'; + + @override + String get quickActions => 'Quick Actions'; + + @override + String get quickOrFullReIndexOf => 'Quick or full re-index of all folders'; + + @override + String get quickScan => 'Quick scan'; + + @override + String get random => 'Random'; + + @override + String get rate => 'Rate'; + + @override + String get rating => 'Rating'; + + @override + String get ratio => 'Ratio'; + + @override + String get rawDsdStreamToDacRequires => + 'Raw DSD stream to DAC. Requires ENCODING_DSD hardware support; otherwise falls back to DoP or PCM automatically.'; + + @override + String get rawPcm => '→ Raw PCM'; + + @override + String get reReadMetadataForEveryFile => + 'Re-read metadata for every file. Slower; use when tags look stale.'; + + @override + String get readMode => 'Read Mode'; + + @override + String get readingTheCoverColors => 'Reading the cover colors…'; + + @override + String readyToRemoveSongKeepingIn(int count, Object kept) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return 'Ready to remove $_temp0 — keeping $kept in total.'; + } + + @override + String recapSavedAs(Object format) { + return 'Recap saved as $format'; + } + + @override + String recentPicksOnHand(Object arg1) { + return '$arg1 recent picks on hand'; + } + + @override + String get recentlyAdded => 'Recently Added'; + + @override + String get recentlyAddedTracksWaitingForMore => + 'Recently added tracks waiting for more play time.'; + + @override + String get recentlyPlayed => 'Recently Played'; + + @override + String get recommended => 'Recommended'; + + @override + String get recommendedOnly => 'Recommended only'; + + @override + String get reconnectAttempts => 'Reconnect Attempts'; + + @override + String get reconnectNow => 'Reconnect Now'; + + @override + String get reconnectToTheInternetToScan => + 'Reconnect to the internet to scan for updates'; + + @override + String get reconnectToWiFiOrMobile => + 'Reconnect to Wi-Fi or mobile data so Flick can scan again'; + + @override + String get reconnectionFailed => 'Reconnection failed'; + + @override + String get reconnectionSuccessful => 'Reconnection successful'; + + @override + String get recorded => 'Recorded'; + + @override + String get refreshAppleMusic => 'Refresh Apple Music'; + + @override + String get refreshDevices => 'Refresh Devices'; + + @override + String get refreshDevices2 => 'Refresh devices'; + + @override + String get refreshMotionArt => 'Refresh Motion Art'; + + @override + String get refreshOutputs => 'Refresh outputs'; + + @override + String get refreshRate => 'Refresh Rate'; + + @override + String get refreshingAppleMusicData => 'Refreshing Apple Music data'; + + @override + String get registeredNotClaimed => 'Registered, not claimed'; + + @override + String get reinitializingPlayback => 'Reinitializing playback…'; + + @override + String get release => 'Release'; + + @override + String get remove => 'Remove'; + + @override + String get removeAll => 'Remove all'; + + @override + String get removeAllSongs => 'Remove All Songs?'; + + @override + String get removeAllSongs2 => 'Remove All Songs'; + + @override + String get removeAllWithBestPicks => 'Remove all with best picks?'; + + @override + String removeAndAllOfItsSongs(Object arg1) { + return 'Remove \"$arg1\" and all of its songs from your library? Files on disk are not deleted.'; + } + + @override + String get removeCustomArt => 'Remove Custom Art'; + + @override + String get removeDuplicates => 'Remove Duplicates'; + + @override + String removeDuplicates2(Object toRemove) { + return 'Remove $toRemove duplicates?'; + } + + @override + String removeDuplicates3(Object toRemove) { + return 'Remove $toRemove duplicates'; + } + + @override + String get removeFolder => 'Remove Folder?'; + + @override + String get removeFromFavorites => 'Remove from Favorites'; + + @override + String get removeFromFavorites2 => 'Remove from favorites'; + + @override + String get removeFromLibrary => 'Remove from Library'; + + @override + String get removeFromPlaylist => 'Remove from Playlist'; + + @override + String get removeSelected => 'Remove selected'; + + @override + String get removeServer => 'Remove server?'; + + @override + String get removeServer2 => 'Remove server'; + + @override + String get removeTheDatabaseEntriesOrDelete => + 'Remove the database entries or delete the files from your device. This cannot be undone.'; + + @override + String get removeTheDatabaseEntryOrDelete => + 'Remove the database entry or delete the file from your device. This cannot be undone.'; + + @override + String get removeTheseSongsFromYourLibrary => + 'Remove these songs from your library. The files on your device will not be affected.'; + + @override + String get removeThisSongFromYourLibrary => + 'Remove this song from your library. The file on your device will not be affected.'; + + @override + String removedCustomAlbumArtFor(Object arg1) { + return 'Removed custom album art for \"$arg1\".'; + } + + @override + String removedCustomAlbumArtFor2(Object arg1) { + return 'Removed custom album art for \"$arg1\".'; + } + + @override + String removedDuplicatesKept(Object arg1, Object arg2) { + return 'Removed $arg1 duplicates — kept $arg2.'; + } + + @override + String removedFromFavorites(Object arg1) { + return 'Removed \"$arg1\" from favorites'; + } + + @override + String removedFromFavorites2(Object arg1) { + return 'Removed $arg1 from favorites'; + } + + @override + String get removedFromFavorites3 => 'Removed from favorites'; + + @override + String removedFromLibrary(Object arg1) { + return 'Removed \"$arg1\" from library'; + } + + @override + String removedSongsFromFavorites(Object arg1) { + return 'Removed $arg1 songs from favorites'; + } + + @override + String removedSongsFromLibrary(Object arg1) { + return 'Removed $arg1 songs from library'; + } + + @override + String get removing => 'Removing…'; + + @override + String get removingDuplicates => 'Removing duplicates…'; + + @override + String get rename => 'Rename'; + + @override + String get renamePreset => 'Rename Preset'; + + @override + String get reorderFilterAndShuffleFromThis => + 'Reorder, filter, and shuffle from this header.'; + + @override + String repeat(Object arg1) { + return 'Repeat: $arg1'; + } + + @override + String get repeatMode => 'Repeat Mode'; + + @override + String get repeatRewind => 'Repeat Rewind'; + + @override + String get replaceAlbumNameWithAVerified => + 'Replace album name with a verified bit-perfect capsule when streaming bit-perfect'; + + @override + String get replay => 'Replay'; + + @override + String get replayCouldnTLoad => 'Replay couldn’t load.'; + + @override + String get replayStudio => 'Replay Studio'; + + @override + String get replayTheTutorialAndFeatureGuide => + 'Replay the tutorial and feature guide'; + + @override + String get replaygain => 'ReplayGain'; + + @override + String get replaygainScan => 'ReplayGain Scan'; + + @override + String get reportedOutputRate => 'Reported Output Rate'; + + @override + String get requestedOutputRate => 'Requested Output Rate'; + + @override + String get requiredToDetectDevicesCodecsAnd => + 'Required to detect devices, codecs, and battery levels'; + + @override + String get resampler => 'Resampler'; + + @override + String get rescanLibrary => 'Rescan Library'; + + @override + String get reset => 'Reset'; + + @override + String get resetArtwork => 'Reset artwork'; + + @override + String get resetArtworkDescription => + 'Re-detect artwork from this album\'s files? Auto-detected covers are replaced with artwork read from the files; custom artwork is kept.'; + + @override + String resetArtworkFor(Object arg1) { + return 'Reset artwork for \"$arg1\".'; + } + + @override + String resetArtworkFor2(Object arg1) { + return 'Reset artwork for \"$arg1\".'; + } + + @override + String get resetCardDesign => 'Reset card design'; + + @override + String get resetDeclinedUsbDacs => 'Reset Declined USB DACs'; + + @override + String get resetDynamics => 'Reset Dynamics'; + + @override + String get resetFx => 'Reset FX'; + + @override + String get resetMiniPlayerToDefaults => 'Reset Mini Player to Defaults'; + + @override + String get resetNavigationToDefaults => 'Reset Navigation to Defaults'; + + @override + String get resetPreferences => 'Reset Preferences'; + + @override + String get resetStreakData => 'Reset streak data?'; + + @override + String get resetStreakData2 => 'Reset Streak Data'; + + @override + String get resetTo0Db => 'Reset to 0 dB'; + + @override + String get resetToDefaults => 'Reset to Defaults'; + + @override + String get resolution => 'Resolution'; + + @override + String get resonance => 'Resonance'; + + @override + String get restart => 'Restart'; + + @override + String get restartRequired => 'Restart required'; + + @override + String get restartTheAppToApplyPlayback => + 'Restart the app to apply playback changes.'; + + @override + String get restartYourDeviceToApplyOutput => + 'Restart your device to apply output format changes.'; + + @override + String get restartingFlick => 'Restarting Flick'; + + @override + String get restoreTheOriginalOrbitalLayout => + 'Restore the original orbital layout'; + + @override + String results(Object arg1) { + return 'Results ($arg1)'; + } + + @override + String get resumeAFamiliarFavoriteOrShuffle => + 'Resume a familiar favorite or shuffle one of the mixes made from your listening.'; + + @override + String get resumeOnReconnect => 'Resume on Reconnect'; + + @override + String get retakePhoto => 'Retake photo'; + + @override + String get retroFuture => 'Retro Future'; + + @override + String get retry => 'Retry'; + + @override + String get reviewBeforeYouClean => 'Review before you clean'; + + @override + String get right => 'Right'; + + @override + String get rightBottom => 'Right (bottom)'; + + @override + String get rightBottomButton => 'Right (Bottom) Button'; + + @override + String get rightTop => 'Right (top)'; + + @override + String get rightTopButton => 'Right (Top) Button'; + + @override + String get ripSource => 'Rip Source'; + + @override + String get root => 'Root'; + + @override + String get rotationSeek => 'rotation seek'; + + @override + String get roundedAlbumArtCardWithA => + 'Rounded album art card with a blurred album-art background.'; + + @override + String get route => 'Route'; + + @override + String get routesBluetoothThroughTheHiRes => + 'Routes Bluetooth through the hi-res Rust engine'; + + @override + String get routesBluetoothThroughTheRustEngine => + 'Routes Bluetooth through the Rust engine'; + + @override + String get runAnotherPlayStoreUpdateScan => + 'Run another Play Store update scan right now'; + + @override + String get runAnotherUpdateScanRightNow => + 'Run another update scan right now'; + + @override + String get rustViaOboe => 'Rust via Oboe'; + + @override + String get rustViaOboeHighRes => 'Rust via Oboe (high-res)'; + + @override + String s(Object arg1) { + return '${arg1}s'; + } + + @override + String s2(Object arg1) { + return '$arg1 s'; + } + + @override + String sAgo(Object arg1) { + return '${arg1}s ago'; + } + + @override + String get sCurve => 'S-Curve'; + + @override + String get sambaWindowsShareTransportPending => 'Samba · Windows share'; + + @override + String get sampleArtist => 'Sample artist'; + + @override + String get samplePreview => 'Sample preview'; + + @override + String get sampleRate => 'Sample rate'; + + @override + String get sampleRate2 => 'Sample Rate'; + + @override + String get sampleRates => 'Sample Rates'; + + @override + String get sampleSongPreviewOnly => 'Sample song · preview only'; + + @override + String get samples => 'Samples'; + + @override + String get save => 'Save'; + + @override + String get saveAsText => 'Save as text'; + + @override + String get saveChanges => 'Save Changes'; + + @override + String get saveConnect => 'Save & Connect'; + + @override + String get saveCreatesAnLrcFileIf => + 'Save creates an `.lrc` file. If some lines are not stamped yet, Flick fills their times automatically so the file stays usable. Lines with fully stamped words export with per-word karaoke timing.'; + + @override + String get saveCurrentAsPreset => 'Save current as preset'; + + @override + String get saveCustomizeReplay => 'Save / customize Replay'; + + @override + String get saveInFlick => 'Save in Flick'; + + @override + String get saveLogs => 'Save logs'; + + @override + String get saveLrcFile => 'Save LRC File'; + + @override + String get saveLrcFile2 => 'Save LRC file'; + + @override + String get saveLyrics => 'Save Lyrics'; + + @override + String get savePng => 'Save PNG'; + + @override + String get savePreset => 'Save Preset'; + + @override + String get saveTheCurrentEqAsJson => 'Save the current EQ as JSON or TXT'; + + @override + String get saved => 'Saved'; + + @override + String get savedAgain => 'Saved · again'; + + @override + String get savedAndVerified => 'Saved and verified'; + + @override + String savedCollections(Object playlistCount) { + return '$playlistCount saved collections'; + } + + @override + String get savedLyricsAndLinkedThemTo => + 'Saved lyrics and linked them to this song.'; + + @override + String get savedLyricsBesideTheSongAs => + 'Saved lyrics beside the song as an `.lrc` file.'; + + @override + String get savedLyricsToTheChosenLocation => + 'Saved lyrics to the chosen location.'; + + @override + String get savedPlaylistsAndQuickJumpsInto => + 'Saved playlists and quick jumps into your library organization.'; + + @override + String get savedToGallery => 'Saved to gallery'; + + @override + String savedToNNNshareIt(Object path) { + return 'Saved to:\n$path\n\nShare it now?'; + } + + @override + String savedToYourGallery(Object arg1) { + return '$arg1 saved to your gallery'; + } + + @override + String get savedVerificationPending => 'Saved (verification pending)'; + + @override + String get saving => 'Saving...'; + + @override + String get saving2 => 'Saving'; + + @override + String get scaleOfTheCenteredFocusedSong => + 'Scale of the centered, focused song card'; + + @override + String get scaleTheAlbumArtCard => 'Scale the album art card'; + + @override + String get scaleTheFullViewAlbumArt => 'Scale the full-view album art card'; + + @override + String get scalesWithWidgetSizeAutomatically => + 'Scales with widget size automatically'; + + @override + String get scanAgain => 'Scan again'; + + @override + String get scanComplete => 'Scan Complete'; + + @override + String get scanFailedPleaseTryAgain => 'Scan failed. Please try again.'; + + @override + String get scanForDevices => 'Scan for devices'; + + @override + String get scanProgress => 'Scan progress'; + + @override + String get scanReplaygain => 'Scan ReplayGain'; + + @override + String get scanningForDuplicates => 'Scanning for duplicates…'; + + @override + String get scanningSettings => 'Scanning Settings'; + + @override + String scanningSongsFound(Object count) { + return 'Scanning... $count songs found'; + } + + @override + String get scanningYourLibrary => 'Scanning your library…'; + + @override + String get scroll => 'Scroll'; + + @override + String get scrollForMore => 'Scroll for more'; + + @override + String get scrollingPausesWhenReducedMotionIs => + 'Scrolling pauses when reduced motion is enabled'; + + @override + String get seamlessTransitionBetweenTracks => + 'Seamless transition between tracks'; + + @override + String get search => 'Search'; + + @override + String get searchAcrossSongsArtistsAndAlbums => + 'Search across songs, artists, and albums instantly.'; + + @override + String get searchAgain => 'Search Again'; + + @override + String get searchArtistTitle => 'Search artist + title...'; + + @override + String get searchArtists => 'Search artists...'; + + @override + String get searchFailed => 'Search failed'; + + @override + String searchFailed2(Object e) { + return 'Search failed: $e'; + } + + @override + String get searchHeadphones => 'Search headphones…'; + + @override + String searchModelCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count models', + one: '$count model', + ); + return 'Search $_temp0…'; + } + + @override + String get searchOnline => 'Search Online'; + + @override + String get searchOnline2 => 'Search online'; + + @override + String get searchOnlineCreateYourOwnSynced => + 'Search online, create your own synced lyrics, or import an existing file.'; + + @override + String get searchOnlineLyrics => 'Search Online Lyrics'; + + @override + String get searchPlayback => 'Search Playback'; + + @override + String get searchResults => 'Search Results'; + + @override + String get searchSongsArtists => 'Search songs, artists...'; + + @override + String get searchSongsArtistsAlbums => 'Search songs, artists, albums...'; + + @override + String get searchTheManual => 'Search the manual...'; + + @override + String get searchYourLibrary => 'Search your library'; + + @override + String get searching => 'Searching…'; + + @override + String get searchingOnline => 'Searching online'; + + @override + String get searchingTheLocalNetwork => 'Searching the local network…'; + + @override + String get secondsOfInactivityBeforeCollapsing => + 'Seconds of inactivity before collapsing'; + + @override + String get seeAll => 'See all'; + + @override + String seeAll2(Object count) { + return 'See all $count'; + } + + @override + String get seeWhatIsNewInThis => 'See what is new in this update'; + + @override + String get select => 'Select'; + + @override + String get selectAFolderToScan => 'Select a folder to scan'; + + @override + String get selectALineAndEdit => + '1. Select a line and edit its timestamp directly, or use \"Use Current Time\".\n2. In the word timeline, drag a boundary to stretch or shrink the segment before it — edits snap to 10ms.\n3. Tap letters in the inspector to split a word into separately timed syllables (slow-then-fast pacing), then drag their boundaries.\n4. Drag the last boundary (or use Length ±) to retime the next line. Use Auto-fill to seed evenly spaced words.\n5. Use the shift controls to move all stamped lyrics together.\n6. Save to generate the final `.lrc` file.'; + + @override + String get selectARelease => 'Select a release'; + + @override + String get selectAll => 'Select All'; + + @override + String get selectAll2 => 'Select all'; + + @override + String get selectDevice => 'Select Device'; + + @override + String selected(Object count) { + return '$count selected'; + } + + @override + String selectedOfSong(Object selected, int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return '$selected selected of $_temp0'; + } + + @override + String get selectedSize => 'Selected Size'; + + @override + String get sep => 'Sep'; + + @override + String get separateFromNavBar => 'Separate from Nav Bar'; + + @override + String get separateTheMiniPlayerToCustomize => + 'Separate the mini player to customize its width and gap. Your custom values are saved while joined.'; + + @override + String get serialNumber => 'Serial Number'; + + @override + String serverPlaylistSyncFailed(Object e) { + return 'Server playlist sync failed: $e'; + } + + @override + String get serverUrl => 'Server URL'; + + @override + String get session => 'Session'; + + @override + String get setAlbumArt => 'Set Album Art'; + + @override + String get setToNow => 'Set to Now'; + + @override + String get settings => 'Settings'; + + @override + String get shadow => 'Shadow'; + + @override + String get shadowJazz => 'Shadow Jazz'; + + @override + String get share => 'Share'; + + @override + String shareFailed(Object e) { + return 'Share failed: $e'; + } + + @override + String get sharedSecret => 'Shared Secret'; + + @override + String get sharpRecommended => 'Sharp (recommended)'; + + @override + String get shiftMetadataTextUpOrDown => 'Shift metadata text up or down'; + + @override + String get shiftOnlyTheAlbumArtUp => 'Shift only the album art up or down'; + + @override + String get shiftOnlyTheSongDetailsUp => + 'Shift only the song details up or down'; + + @override + String get showASystemOverlayMiniPlayer => + 'Show a system overlay mini-player over other apps'; + + @override + String get showAThinPlaybackProgressLine => + 'Show a thin playback progress line'; + + @override + String get showAlbum => 'Show album'; + + @override + String get showAlbum2 => 'Show Album'; + + @override + String get showAlbumArtwork => 'Show album artwork.'; + + @override + String get showAlbumArtworkOnTheMini => + 'Show album artwork on the mini player'; + + @override + String get showArtist => 'Show artist'; + + @override + String get showArtist2 => 'Show Artist'; + + @override + String get showArtistBelowSongTitle => 'Show artist below song title'; + + @override + String get showFileInfo => 'Show file info'; + + @override + String get showFileInfo2 => 'Show File Info'; + + @override + String get showFrame => 'Show frame'; + + @override + String get showFrame2 => 'Show Frame'; + + @override + String get showGlow => 'Show Glow'; + + @override + String get showLabels => 'Show Labels'; + + @override + String get showLess => 'Show less'; + + @override + String get showLyrics => 'Show lyrics'; + + @override + String get showMore => 'Show more'; + + @override + String get showMoreArtByFadingOnly => + 'Show more art by fading only the bottom of the header and lowering body content'; + + @override + String get showOrHideHomeScreenSections => + 'Show or hide home screen sections'; + + @override + String get showOrbitPath => 'Show Orbit Path'; + + @override + String get showOtherArtistsOnAlbumPages => + 'Show other artists on album pages'; + + @override + String get showPassword => 'Show password'; + + @override + String get showPlaylistPreviewsOnTheHome => + 'Show playlist previews on the home screen'; + + @override + String get showRecentlyPlayedArtistsOnThe => + 'Show recently played artists on the home screen'; + + @override + String get showRelatedAlbumsOnAlbumPages => + 'Show related albums on album pages'; + + @override + String get showSmartMixesGeneratedFromYour => + 'Show smart mixes generated from your listening habits'; + + @override + String get showTheArtistBelowTheSong => + 'Show the artist below the song title'; + + @override + String get showTheAtAGlanceSummary => + 'Show the \"at a glance\" summary on Artists/Albums'; + + @override + String get showTheAudioEnginePickerCard => + 'Show the audio engine picker card on the home screen'; + + @override + String get showTheAudioVisualizerOffSaves => + 'Show the audio visualizer (off saves battery)'; + + @override + String get showTheBrowseChipsForLibrary => + 'Show the browse chips for library sections on the home screen'; + + @override + String get showTheFloatingMiniPlayerPill => + 'Show the floating mini-player pill on screens'; + + @override + String get showTheGlassFrameAroundAlbum => + 'Show the glass frame around album art'; + + @override + String get showTheGridOfShortcutCards => + 'Show the grid of shortcut cards on the home screen'; + + @override + String get showTheMiniPlayerAsIts => + 'Show the mini player as its own bar above the buttons'; + + @override + String get showTheNumberOverBlurredArt => 'Show the number over blurred art.'; + + @override + String showTheTabInTheBottom(Object arg1) { + return 'Show the $arg1 tab in the bottom bar'; + } + + @override + String get showTheTrackNumber => 'Show the track number.'; + + @override + String get showTheUsbVolumeBarOn => + 'Show the USB volume bar on the home screen'; + + @override + String get showTheUsbVolumeBarOn2 => + 'Show the USB volume bar on the UAC2 settings screen'; + + @override + String get showTitle => 'Show title'; + + @override + String get showTitle2 => 'Show Title'; + + @override + String get showVerboseAudioDiagnosticsAndEngine => + 'Show verbose audio diagnostics and engine/session trace logs.'; + + @override + String get showVisualizer => 'Show visualizer'; + + @override + String get showYourRecentListeningHistoryOn => + 'Show your recent listening history on the home screen'; + + @override + String showingAllAlbums(Object totalCount) { + return 'Showing all $totalCount albums'; + } + + @override + String showingOfAlbums(Object visibleCount, Object totalCount) { + return 'Showing $visibleCount of $totalCount albums'; + } + + @override + String get showingYourLastLoadedReplay => 'Showing your last loaded Replay.'; + + @override + String get shownWhenThereIsRoomBeside => + 'Shown when there is room beside the controls'; + + @override + String get showsWhatSPlayingTapTo => + 'Shows what\'s playing. Tap to open the full player.'; + + @override + String get shuffle => 'Shuffle'; + + @override + String shuffle2(Object arg1) { + return 'Shuffle: $arg1'; + } + + @override + String get shuffleFavorites => 'Shuffle Favorites'; + + @override + String get shuffleMode => 'Shuffle Mode'; + + @override + String get shuffleSongsAndJumpBetweenCategories => + 'Shuffle songs and jump between categories'; + + @override + String get shuffleSongsInCurrentList => 'Shuffle songs in current list'; + + @override + String get signInFailedRetry => 'Sign-in Failed — Retry'; + + @override + String get signInWithTidal => 'Sign in with Tidal'; + + @override + String get signInWithYourAccountHifi => + 'Sign in with your account · HiFi lossless'; + + @override + String get signInWithYourOwnTidal => + 'Sign in with your own Tidal account. HiFi lossless (FLAC/ALAC) plays through the bit-perfect engine; HiRes/MQA and Atmos are gated by Tidal and will show an error instead of playing.'; + + @override + String get signal => 'Signal'; + + @override + String get signalAccurateUnverified => 'AccurateRip not verified'; + + @override + String get signalAccurateVerified => 'AccurateRip verified in log'; + + @override + String get signalAltSetting => 'Alt setting'; + + @override + String get signalBufferCapacity => 'Buffer capacity'; + + @override + String get signalBufferFill => 'Buffer fill'; + + @override + String get signalBufferOccupancy => 'Buffer occupancy at open'; + + @override + String get signalBufferTarget => 'Buffer target'; + + @override + String get signalCopyCrc => 'Copy CRC'; + + @override + String get signalCrcCannotCompare => 'Cannot compare'; + + @override + String get signalCrcComparison => 'CRC comparison'; + + @override + String get signalCrcMatch => 'Match'; + + @override + String get signalCrcMismatch => 'Mismatch'; + + @override + String get signalDriftFromTarget => 'Drift from target'; + + @override + String get signalDsdBitRate => 'DSD bit rate'; + + @override + String get signalFileFormat => 'File format'; + + @override + String get signalFramesPerPacket => 'Frames / packet'; + + @override + String get signalMaxPacket => 'Max packet'; + + @override + String get signalNoRipDescription => + 'No ripping or verification information was found for this track.'; + + @override + String get signalNotReported => 'Not reported'; + + @override + String get signalNotVerified => 'Not verified'; + + @override + String get signalRecordingUnavailable => 'Rip history unavailable'; + + @override + String get signalRipDescription => + 'Information from the rip log, not a stage of the current playback path.'; + + @override + String get signalRipProvenance => 'Rip provenance'; + + @override + String get signalRipper => 'Ripper'; + + @override + String get signalServiceInterval => 'Service interval'; + + @override + String get signalSnapshot => 'Snapshot'; + + @override + String get signalSnapshotAtOpen => 'Snapshot at open'; + + @override + String get signalSourceDescription => + 'Properties of the source file, not the output sent to the device.'; + + @override + String get signalSourceDetails => 'Source format details'; + + @override + String get signalSubslot => 'Subslot'; + + @override + String get signalSyncType => 'Sync type'; + + @override + String get signalTarget => 'target'; + + @override + String get signalTestCrc => 'Test CRC'; + + @override + String get signalTransportFormat => 'Transport'; + + @override + String get signalUnderruns => 'Underruns'; + + @override + String get signalUsageType => 'Usage type'; + + @override + String get signalUsbDescription => + 'Transport values available when this sheet opened. This is not a live packet trace.'; + + @override + String get signalUsbMissingDescription => + 'URB details are only reported for the direct USB path. No transfer activity is inferred.'; + + @override + String get signalUsbTransport => 'USB transport'; + + @override + String get signalUsbUnavailable => 'USB transport details unavailable'; + + @override + String get signalVerificationMissing => 'Verification not reported'; + + @override + String get signalVerifiedInLog => 'Verified in log'; + + @override + String get signedIn => 'Signed in'; + + @override + String get silkySmoothBZierCurvesFluid => + 'Silky smooth Bézier curves — fluid and organic'; + + @override + String get similarArtists => 'Similar Artists'; + + @override + String get simple => 'Simple'; + + @override + String get simpleMode => 'Simple mode'; + + @override + String get simplifiedChinese => 'Simplified Chinese'; + + @override + String get single => 'Single'; + + @override + String get size => 'Size'; + + @override + String get sizing => 'Sizing'; + + @override + String get skip => 'Skip'; + + @override + String get skipUnsupportedFilesAndHiddenNomedia => + 'Skip unsupported files and hidden .nomedia directories'; + + @override + String skippedUnmatchedEntr(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count unmatched entries', + one: '$count unmatched entry', + ); + return ' Skipped $_temp0.'; + } + + @override + String get sleepTimer => 'Sleep timer'; + + @override + String get sleepTimer2 => 'Sleep Timer'; + + @override + String get sleeves => 'Sleeves'; + + @override + String get slope => 'Slope'; + + @override + String get smbSharesCanBeAddedNow => + 'SMB2/3 shares connect through the built-in client. Enter the share URL (smb://host/share) and sign in if the server asks for it.'; + + @override + String get smooth => 'Smooth'; + + @override + String get smoothsPeaksAndRaisesBodyBefore => + 'Smooths peaks and raises body before the limiter catches transients.'; + + @override + String get snappy => 'Snappy'; + + @override + String get softDetailBalanced => 'Soft detail, balanced'; + + @override + String get softHighlightBehindTheSelectedSong => + 'Soft highlight behind the selected song'; + + @override + String get softwareAppControlled => 'Software (App-controlled)'; + + @override + String get solid => 'Solid'; + + @override + String get soloDeveloper => 'Solo Developer'; + + @override + String get someOnlineFeaturesMayNotWork => + ' · Some online features may not work'; + + @override + String get someWordsAreStillUntimedFinish => + 'Some words are still untimed. Finish capturing in Word Sync mode.'; + + @override + String get somethingWentWrong => 'Something went wrong'; + + @override + String song2(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return '$_temp0'; + } + + @override + String song3(int count, Object server) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return '$_temp0 · $server'; + } + + @override + String get songActions => 'Song actions'; + + @override + String get songArtist => 'Song Artist'; + + @override + String get songCount => 'Song Count'; + + @override + String get songGestures => 'Song Gestures'; + + @override + String get songMetadata => 'Song Metadata'; + + @override + String get songTitle => 'Song Title'; + + @override + String songUnit(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'songs', + one: 'song', + ); + return '$_temp0'; + } + + @override + String get songViewList => 'Song View: List'; + + @override + String get songViewOrbital => 'Song View: Orbital'; + + @override + String songs(Object arg1, Object arg2) { + return '$arg1 • $arg2 songs'; + } + + @override + String songs12(Object arg1) { + return '$arg1 songs'; + } + + @override + String songs13(Object count) { + return '$count songs'; + } + + @override + String get songs14 => 'Songs'; + + @override + String songs15(Object arg1) { + return '$arg1 songs'; + } + + @override + String songs2(Object songCount) { + return '$songCount songs'; + } + + @override + String songs3(Object arg1) { + return '$arg1 songs'; + } + + @override + String songs4(Object _totalSongs) { + return '$_totalSongs songs'; + } + + @override + String songs5(Object arg1) { + return '$arg1 songs'; + } + + @override + String songs9(Object arg1) { + return '$arg1 songs'; + } + + @override + String songsAlbums(Object arg1, Object uniqueAlbums) { + return '$arg1 songs • $uniqueAlbums albums'; + } + + @override + String songsAlbums2(Object arg1, Object albumCount) { + return '$arg1 songs · $albumCount albums'; + } + + @override + String get songsBeforeTheTappedTrackQueue => + 'Songs before the tapped track queue at the end'; + + @override + String get songsCategories => 'Songs & Categories'; + + @override + String songsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs', + one: '$count song', + ); + return '$_temp0'; + } + + @override + String songsFound(Object arg1) { + return '$arg1 songs found'; + } + + @override + String songsIn(int songs, int folders) { + String _temp0 = intl.Intl.pluralLogic( + songs, + locale: localeName, + other: '$songs songs', + one: '$songs song', + ); + String _temp1 = intl.Intl.pluralLogic( + folders, + locale: localeName, + other: '$folders folders', + one: '$folders folder', + ); + return '$_temp0 in $_temp1'; + } + + @override + String songsInRotation(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count songs in your rotation', + one: '$count song in your rotation', + ); + return '$_temp0'; + } + + @override + String get songsTab => 'Songs Tab'; + + @override + String songsU2022Albums(Object arg1, Object uniqueAlbums) { + return '$arg1 songs • $uniqueAlbums albums'; + } + + @override + String get songsYouPlayWillAppearHere => 'Songs you play will appear here'; + + @override + String get songsYouScanIntoYourLibrary => + 'Songs you scan into your library will show up here'; + + @override + String get sortBy => 'SORT BY'; + + @override + String get sortFilter => 'Sort & Filter'; + + @override + String get sortSongs => 'Sort songs'; + + @override + String get source => 'Source'; + + @override + String get sourceRate => 'Source rate'; + + @override + String get spaceBetweenTheTwoBars => 'Space between the two bars'; + + @override + String get spaceOdyssey => 'Space Odyssey'; + + @override + String get spatialTime => 'Spatial & Time'; + + @override + String get speedUp => 'Speed up'; + + @override + String get springPhysicsEnergeticAndReactive => + 'Spring physics — energetic and reactive'; + + @override + String get squareRoot => 'Square Root'; + + @override + String get stampNext => 'Stamp & Next'; + + @override + String get stampNow => 'Stamp Now'; + + @override + String get stampThisLineFirstToEdit => + 'Stamp this line first to edit its word timeline.'; + + @override + String get standard => 'Standard'; + + @override + String get standard60hz => 'Standard (60Hz)'; + + @override + String get standardBluetoothRoutingViaAndroid => + 'Standard Bluetooth routing via Android'; + + @override + String get standardEngine => 'Standard Engine'; + + @override + String get starlightSerenade => 'Starlight Serenade'; + + @override + String get start => 'Start'; + + @override + String get startAtNow => 'Start at Now'; + + @override + String get startBuildingYourHome => 'Start Building Your Home'; + + @override + String get startPlayingToPopulateThisSpace => + 'Start playing to populate this space'; + + @override + String get startStreaming => 'Start Streaming'; + + @override + String get startedPresetDownload => 'Started preset download.'; + + @override + String get state => 'State'; + + @override + String get status => 'Status'; + + @override + String get stepByStepWalkthroughOfThe => + 'Step-by-step walkthrough of the app'; + + @override + String get stereo => 'Stereo'; + + @override + String get stop => 'Stop'; + + @override + String get stopAtTheEndOfThe => 'Stop at the end of the current list'; + + @override + String get stopCasting => 'Stop Casting'; + + @override + String get stopStreaming => 'Stop Streaming'; + + @override + String get stopUsbOnQuit => 'Stop USB on Quit'; + + @override + String get stopWhenTheQueueEnds => 'Stop when the queue ends'; + + @override + String stoppingIn(Object arg1) { + return 'Stopping in $arg1'; + } + + @override + String get storage => 'Storage'; + + @override + String get storageAccessIsRequiredToScan => + 'Storage access is required to scan and read music files, extract metadata, import/export EQ presets, and save recap images. All processing happens on-device.'; + + @override + String get storagePermissionIsRequiredToAdd => + 'Storage permission is required to add music folders'; + + @override + String get storagePermissions => 'Storage Permissions'; + + @override + String get storeOn => 'Store on'; + + @override + String get storedAsASaltedHashNever => + 'Stored as a salted hash, never in plaintext'; + + @override + String get storedEncodedPlaybackUnavailableInThis => + 'Stored base64-encoded — required for NTLM sign-in'; + + @override + String get stormChasers => 'Storm Chasers'; + + @override + String get strategy => 'Strategy'; + + @override + String get stream => 'Stream'; + + @override + String get streamConfigurationNotAvailable => + 'Stream configuration not available'; + + @override + String get streamStable => 'Stream stable'; + + @override + String get streaming => 'Streaming'; + + @override + String get streamingFromQueue => 'Streaming from queue'; + + @override + String get stretchNonSquareArt => 'Stretch Non-Square Art'; + + @override + String get strong => 'Strong'; + + @override + String get studioGradeOutputForExternalDacs => + 'Studio-grade output for external DACs and headphone amps. Bypasses Android\'s audio processing for pure sound.'; + + @override + String get sub => 'Sub'; + + @override + String subfolderCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count subfolders', + one: '$count subfolder', + ); + return '$_temp0'; + } + + @override + String get subsonic => 'Subsonic'; + + @override + String get subsonicServersSyncAndStreaming => + 'Subsonic servers, sync, and streaming'; + + @override + String get subtle => 'Subtle'; + + @override + String get support => 'Support'; + + @override + String get supportDevelopmentOnBuyMeACoffee => + 'Support development on Buy Me a Coffee'; + + @override + String get supportDevelopmentOnKoFi => 'Support development on Ko-fi'; + + @override + String get supportFlick => 'Support Flick'; + + @override + String get supportFlickOnKoFi => 'Support Flick on Ko-fi'; + + @override + String get surfaceShading => 'Surface shading'; + + @override + String get sweepAHighlightThroughWordsAs => + 'Sweep a highlight through words as they are sung'; + + @override + String get swipe => 'Swipe'; + + @override + String get swipeActions => 'Swipe Actions'; + + @override + String get swipeHorizontallyToFineTuneEach => + 'Swipe horizontally to fine-tune each center band.'; + + @override + String get swipeLeftRightToSkipTracks => 'Swipe left/right to skip tracks'; + + @override + String get swipeLeftToUnfavoriteASong => 'Swipe left to unfavorite a song'; + + @override + String get swipeSongsLeftToQueueOr => + 'Swipe songs left to queue or right to favorite'; + + @override + String get swipeToShowOrHideThe => 'Swipe to show or hide the visualizer'; + + @override + String get switchSongs => 'Switch Songs'; + + @override + String get switchToTheExclusiveUsbPath => + 'Switch to the exclusive USB path automatically when a DAC is attached. Declined DACs are remembered.'; + + @override + String get switchedBackToTheAutomaticLyrics => + 'Switched back to the automatic lyrics source.'; + + @override + String get syllablesTapALetterToSplit => + 'Syllables — tap a letter to split or merge:'; + + @override + String get symmetricalBarsMirroredFromTheCenter => + 'Symmetrical bars mirrored from the center'; + + @override + String syncFailed(Object e) { + return 'Sync failed: $e'; + } + + @override + String get syncNow => 'Sync now'; + + @override + String get syncServerPlaylists => 'Sync Server Playlists'; + + @override + String get synced => 'Synced'; + + @override + String synced2(Object arg1) { + return 'Synced $arg1'; + } + + @override + String get syncedLrc => 'Synced LRC'; + + @override + String syncedPlaylistFromServers(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count playlists', + one: '$count playlist', + ); + return 'Synced $_temp0 from servers'; + } + + @override + String get syncing => 'Syncing…'; + + @override + String get synthwaveCity => 'Synthwave City'; + + @override + String get system => 'System'; + + @override + String get systemAndroidMixer => 'System (Android mixer)'; + + @override + String get tagsWereWrittenButCouldNot => + 'Tags were written but could not be confirmed by re-reading the file. A library rescan will reconcile any difference.'; + + @override + String tap(Object label) { + return 'Tap: \"$label\"'; + } + + @override + String get tapABandToExpandDrag => + 'Tap a band to expand. Drag a knob to adjust. Tap a value to type directly.'; + + @override + String get tapAllOrEnableAChip => 'Tap All or enable a chip to see results'; + + @override + String get tapChipsToFilterCategories => 'Tap chips to filter categories'; + + @override + String get tapEditTextTopRight => + '1. Tap \"Edit Text\" (top right) and paste the lyrics — one line per row.\n2. Play the song.\n3. Pick the current line in the Lines list.\n4. Tap \"Stamp & Next\" when you hear that line.\n5. Save when done.'; + + @override + String get tapIconsToSwitchTabsLong => + 'Tap icons to switch tabs. Long-press to customize the bar.'; + + @override + String get tapTheHeartIconOnAny => + 'Tap the heart icon on any song\nto add it to your favorites'; + + @override + String get tapTheMiniPlayerForWaveform => + 'Tap the mini player for waveform seekbar, EQ, lyrics, and visualizer.'; + + @override + String get tapToInspect12602280Png => 'Tap to inspect · 1260 × 2280 PNG'; + + @override + String get tapToPlayLongPressFor => + 'Tap to play, long-press for options (queue, play next, info).'; + + @override + String get tapToPreview => 'Tap to preview'; + + @override + String targetMs(Object arg1) { + return 'target $arg1 ms'; + } + + @override + String get tempo => 'Tempo'; + + @override + String tempoX(Object arg1) { + return 'Tempo ${arg1}x'; + } + + @override + String test(Object arg1) { + return 'Test: $arg1'; + } + + @override + String get testConnection => 'Test Connection'; + + @override + String get textGestures => 'Text & Gestures'; + + @override + String get textPlacement => 'Text placement'; + + @override + String get textPlacement2 => 'Text Placement'; + + @override + String get textSize => 'Text size'; + + @override + String get textSize2 => 'Text Size'; + + @override + String get thatSTheTour => 'That\'s the tour!'; + + @override + String get theAppDoesNotKnowinglyCollect => + 'The app does not knowingly collect any information from anyone, regardless of age.'; + + @override + String get theAppQueriesPublicApisMusicbrainz => + 'The app queries public APIs (MusicBrainz/Cover Art Archive, iTunes, Deezer) to find matching album art. Search queries use local music metadata. Downloaded images are cached locally.'; + + @override + String get theAudioEngineDeterminesHowYour => + 'The audio engine determines how your music is played back. Each option balances reliability, quality, and compatibility differently.'; + + @override + String get theIsochronousUsbEngineWillBe => + 'The Isochronous USB engine will be stopped when the app quits.'; + + @override + String get theIsochronousUsbEngineWillStay => + 'The Isochronous USB engine will stay alive when the app quits.'; + + @override + String get theNamesShowingUpAgainAnd => + 'The names showing up again and again in your recent queue.'; + + @override + String get thePosterIsNotReadyYet => + 'The poster is not ready yet. Try saving again.'; + + @override + String get theTracksDominatingYourWeeklyAnd => + 'The tracks dominating your weekly and monthly recap.'; + + @override + String get thisAppIsBuiltByA => + 'This app is built by a solo developer with zero budget. If you love high-fidelity audio, consider supporting its development on Ko-fi.'; + + @override + String get thisClearsYourCurrentDayStreak => + 'This clears your current day streak and any unlocked streak milestones. This cannot be undone.'; + + @override + String get thisDevice => 'This device'; + + @override + String get thisFolderAppearsToBeEmpty => 'This folder appears to be empty'; + + @override + String get thisMonth => 'This Month'; + + @override + String get thisMonthSRecap => 'This Month\'s Recap'; + + @override + String thisRemovesAllEntriesFromMemory(Object arg1) { + return 'This removes all $arg1 entries from memory.'; + } + + @override + String get thisSlowsPlaybackTo432440 => + 'This slows playback to 432/440 (~1.8% lower pitch and tempo) and disables bit-perfect passthrough. Music will sound slightly lower in tone. Only enable this if you intentionally want A=432 tuning.'; + + @override + String get thisSongHasNoFilePath => + 'This song has no file path and cannot be edited.'; + + @override + String get thisSongIsMissingAlbumMetadata => + 'This song is missing album metadata, so online matching is limited.'; + + @override + String get thisSongOnly => 'This song only'; + + @override + String get thisWeek => 'This Week'; + + @override + String get thisWeekSRecap => 'This Week\'s Recap'; + + @override + String get thisYearSRecap => 'This Year\'s Recap'; + + @override + String get threshold => 'Threshold'; + + @override + String get thunderRoad => 'Thunder Road'; + + @override + String get tidal => 'Tidal'; + + @override + String get time => 'Time'; + + @override + String get timeShift => 'Time Shift'; + + @override + String get timestamp => 'Timestamp'; + + @override + String get tips => 'Tips'; + + @override + String get title => 'Title'; + + @override + String get toRemove => 'To remove'; + + @override + String get today => 'Today'; + + @override + String get todaySRecap => 'Today\'s Recap'; + + @override + String get toneControls => 'Tone Controls'; + + @override + String get tools => 'Tools'; + + @override + String get top => 'Top'; + + @override + String get topAlbum => 'Top album'; + + @override + String get topArtist => 'Top artist'; + + @override + String get topArtists => 'Top artists'; + + @override + String get topSongs => 'Top Songs'; + + @override + String get topSongs2 => 'Top songs'; + + @override + String get total => 'Total'; + + @override + String get track => 'Track'; + + @override + String track2(Object arg1) { + return 'Track $arg1'; + } + + @override + String get track3 => 'Track #'; + + @override + String get trackBitDepth => 'Track Bit Depth'; + + @override + String get trackChannels => 'Track Channels'; + + @override + String get trackConsecutiveListeningDaysAndShow => + 'Track consecutive listening days and show the popup'; + + @override + String get trackCount => 'Track Count'; + + @override + String get trackDsdRate => 'Track DSD Rate'; + + @override + String get trackNumber => 'Track Number'; + + @override + String get trackSampleRate => 'Track Sample Rate'; + + @override + String get trackThumbnails => 'Track Thumbnails'; + + @override + String get trackTime => 'Track time'; + + @override + String get trackTimeSumsTheFullDuration => + 'Track time sums the full duration of logged plays.'; + + @override + String tracks(Object _totalTracks) { + return '$_totalTracks tracks'; + } + + @override + String tracks2(Object arg1) { + return '$arg1 tracks'; + } + + @override + String tracks3(Object arg1) { + return '$arg1 tracks'; + } + + @override + String tracks4(Object arg1) { + return '$arg1 tracks'; + } + + @override + String tracks5(Object arg1, Object arg2) { + return '$arg1 · $arg2 tracks'; + } + + @override + String tracks6(Object arg1) { + return '$arg1 tracks'; + } + + @override + String tracks7(Object trackCount, Object arg1) { + return '$trackCount tracks • $arg1'; + } + + @override + String tracks8(Object arg1) { + return '$arg1 tracks'; + } + + @override + String tracksLikedSongsPlaylists( + Object songCount, + Object favoriteCount, + Object playlistCount, + ) { + return '$songCount tracks, $favoriteCount liked songs, $playlistCount playlists'; + } + + @override + String tracksReadyToRevisit(Object favoritesCount) { + return '$favoritesCount tracks ready to revisit'; + } + + @override + String get tracksThatFitTheQuieterSide => + 'Tracks that fit the quieter side of your listening habits.'; + + @override + String get transparent => 'Transparent'; + + @override + String get treble => 'Treble'; + + @override + String get trueRandomMayRepeatBeforeList => + 'True random (may repeat before list ends)'; + + @override + String get truncate => 'Truncate'; + + @override + String get tryAdjustingYourSearchQuery => 'Try adjusting your search query'; + + @override + String get tryAgain => 'Try again'; + + @override + String get tryAnotherKeywordOrEnableMore => + 'Try another keyword or enable more categories'; + + @override + String get tryOriginalSearch => 'Try original search'; + + @override + String get tryPickingALocalImageIf => + 'Try picking a local image if the release metadata is uncommon.'; + + @override + String get turnOff432HzTuningTo => 'Turn off 432 Hz tuning to use crossfade'; + + @override + String get turnOff432HzTuningTo2 => 'Turn off 432 Hz tuning to use crossfeed'; + + @override + String get typeABrandAndModelTo => 'Type a brand and model to search online.'; + + @override + String get u162ByteSubslotsLlRr => 'U16 — 2-byte subslots, LL|RR'; + + @override + String u2022(Object arg1, Object valueLabel) { + return '$arg1 • $valueLabel'; + } + + @override + String u20223(Object arg1, Object gainLabel) { + return '$arg1 • $gainLabel'; + } + + @override + String u2022Bit(Object arg1) { + return ' • $arg1-bit'; + } + + @override + String get u324ByteSubslotsLlllRrrr => + 'U32 — 4-byte subslots, LLLL|RRRR (legacy)'; + + @override + String get u8ByteInterleavedLrlr => 'U8 — byte-interleaved LRLR'; + + @override + String get u8ByteInterleavedRecommendedDefault => + 'U8 — byte-interleaved, recommended default'; + + @override + String get uac2AndEqualizer => 'UAC2 and equalizer'; + + @override + String get uac2IsNotAvailableOnThis => + 'UAC2 is not available on this platform'; + + @override + String get uac2NotAvailableOnThisPlatform => + 'UAC2 not available on this platform'; + + @override + String get uac2Preferences => 'UAC2 Preferences'; + + @override + String get uac2PreferencesResetSuccessfully => + 'UAC2 preferences reset successfully'; + + @override + String get uiCustomization => 'UI Customization'; + + @override + String get ultra => 'Ultra'; + + @override + String get unableToCheckForUpdatesRight => + 'Unable to check for updates right now.'; + + @override + String get unableToLoadPatchNotesRight => + 'Unable to load patch notes right now.'; + + @override + String get unableToOpenAllFilesAccess => + 'Unable to open All Files Access settings'; + + @override + String get unableToOpenBatteryOptimizationSettings => + 'Unable to open battery optimization settings'; + + @override + String unavailable(Object featureName) { + return '$featureName Unavailable'; + } + + @override + String get unavailable2 => 'Unavailable'; + + @override + String underruns(Object arg1) { + return '$arg1 underruns'; + } + + @override + String get undo => 'Undo'; + + @override + String get unfavorite => 'Unfavorite'; + + @override + String get unfavoriteSelected => 'Unfavorite selected'; + + @override + String get uniqueArtists => 'Unique Artists'; + + @override + String get universalCompatibility => 'Universal compatibility'; + + @override + String get unknown => 'Unknown'; + + @override + String get unknownAlbum => 'Unknown Album'; + + @override + String get unknownArtist => 'Unknown Artist'; + + @override + String get unknownBitrate => 'Unknown bitrate'; + + @override + String get unknownFolder => 'Unknown Folder'; + + @override + String get unknownTitle => 'Unknown Title'; + + @override + String get unknownTrack => 'Unknown Track'; + + @override + String unlocked(Object unlocked, Object arg1) { + return '$unlocked / $arg1 unlocked'; + } + + @override + String unlocked3(Object _milestonesUnlocked, Object arg1) { + return '$_milestonesUnlocked / $arg1 unlocked'; + } + + @override + String get unmute => 'Unmute'; + + @override + String get unreported => 'Unreported'; + + @override + String get unsavedChanges => 'Unsaved Changes'; + + @override + String up(Object arg1) { + return '$arg1 up'; + } + + @override + String get upNext => 'Up next'; + + @override + String upcomingSong(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count upcoming songs', + one: '$count upcoming song', + ); + return '$_temp0'; + } + + @override + String get update => 'Update'; + + @override + String get updateAvailable => 'Update Available'; + + @override + String get updateAvailableDownloadFromFlickPlayer => + 'Update available — download from flick-player.site'; + + @override + String get updateAvailableOnThePlayStore => + 'Update available on the Play Store.'; + + @override + String get updateNoticeHidden => 'Update notice hidden.'; + + @override + String updated(Object arg1) { + return 'Updated $arg1'; + } + + @override + String updatedAlbumArtFor(Object arg1) { + return 'Updated album art for \"$arg1\".'; + } + + @override + String updatedAlbumArtFor2(Object arg1) { + return 'Updated album art for \"$arg1\".'; + } + + @override + String get updates => 'Updates'; + + @override + String get updatesAboutAndSupport => 'Updates, about, and support'; + + @override + String get upload => 'Upload'; + + @override + String uploadFailed(Object arg1) { + return 'Upload failed ($arg1).'; + } + + @override + String uploadFailed2(Object e) { + return 'Upload failed: $e'; + } + + @override + String get uploadLogsAsALink => 'Upload logs as a link?'; + + @override + String get upnpDlna => 'UPnP / DLNA'; + + @override + String get urbPacket => 'URB Packet'; + + @override + String get urbTransfer => 'URB Transfer'; + + @override + String get urbanEchoes => 'Urban Echoes'; + + @override + String get usbAudioClass20Devices => + 'USB Audio Class 2.0 devices (external DACs/AMPs) are accessed locally for bit-perfect audio playback. No USB device information is transmitted externally.'; + + @override + String get usbAudioDevice => 'USB Audio Device'; + + @override + String get usbAudioDevices => 'USB Audio Devices'; + + @override + String get usbAudioError => 'USB Audio Error'; + + @override + String get usbAudioUac2 => 'USB Audio (UAC2)'; + + @override + String get usbDacAutoBitPerfectOffers => + 'USB DAC auto bit-perfect offers reset.'; + + @override + String get usbDacsHeadphonesAndReferenceGear => + 'USB DACs, headphones, and reference gear to test and improve playback quality.'; + + @override + String get usbDeviceAccess => 'USB Device Access'; + + @override + String get usbNotConnected => 'USB not connected'; + + @override + String get usbRouteVolume => 'USB Route Volume'; + + @override + String get usbStorageNotConnected => 'USB storage not connected'; + + @override + String get usbVolume => 'USB Volume'; + + @override + String get usbVolumeInSettings => 'USB Volume in Settings'; + + @override + String get usbVolumeOnHome => 'USB Volume on Home'; + + @override + String get useAFixed48khz16bitOutput => + 'Use a fixed 48kHz/16bit output for better compatibility'; + + @override + String get useAaudioDirectlyLowestLatencyOn => + 'Use AAudio directly. Lowest latency on Android 8.1 and newer.'; + + @override + String get useAlbumArtAsBackground => 'Use album art as background'; + + @override + String get useAutoSource => 'Use Auto Source'; + + @override + String get useCurrentTime => 'Use Current Time'; + + @override + String get useExistingFile => 'Use Existing File'; + + @override + String get useExistingFileInTheLyrics => + '- \"Use Existing File\" in the lyrics panel links an `.lrc`, `.txt`, or `.xml` file.\n- If some lines are not stamped, Flick fills their times automatically.\n- Save writes beside the song when possible, otherwise Flick stores a linked copy.'; + + @override + String get useFilesystemLevelScanningInsteadOf => + 'Use filesystem-level scanning instead of MediaStore for full tag accuracy'; + + @override + String get useMmSsCcEG => 'Use mm:ss.cc, e.g. 01:23.45'; + + @override + String get useTheCurrentAudioFileS => + 'Use the current audio file\'s name when saving lyrics internally'; + + @override + String get useTheDefaultMonochromeTheme => + 'Use the default monochrome theme.'; + + @override + String get useTheHighestFixedOutputRate => + 'Use the highest fixed output rate and bit depth available'; + + @override + String get useTheLegacyOpenslEsBackend => + 'Use the legacy OpenSL ES backend. Troubleshooting fallback for older or problematic devices.'; + + @override + String get useTheListSongsBrowser => 'Use the list songs browser'; + + @override + String get useTheOrbitalSongsBrowser => 'Use the orbital songs browser'; + + @override + String get useTheVerifiedDirectUsbPath => + 'Use the verified direct USB path and disable software DSP controls that would break bit-perfect playback on an external USB DAC.'; + + @override + String get userToken => 'User Token'; + + @override + String get username => 'Username'; + + @override + String using(Object arg1) { + return 'Using $arg1'; + } + + @override + String using2(Object arg1) { + return 'Using $arg1'; + } + + @override + String get variableBitrateLowLatency => 'Variable bitrate, low latency'; + + @override + String get variousArtists2 => 'Various Artists'; + + @override + String get velvetNoir => 'Velvet Noir'; + + @override + String get vendorId => 'Vendor ID'; + + @override + String get verboseDartRustAndCrashLogs => + 'Verbose Dart, Rust, and crash logs'; + + @override + String get verified => 'Verified'; + + @override + String version(Object kAppVersion) { + return 'Version $kAppVersion'; + } + + @override + String version2(Object arg1) { + return 'Version $arg1'; + } + + @override + String get verticalBarsClassicSpectrumAnalyzer => + 'Vertical bars — classic spectrum analyzer'; + + @override + String get verticalBarsThatAnimateAcrossThe => + 'Vertical bars that animate across the screen.'; + + @override + String get verticalPosition => 'Vertical Position'; + + @override + String get vibrant => 'Vibrant'; + + @override + String get viewAsGrid => 'View as grid'; + + @override + String get viewAsList => 'View as list'; + + @override + String get viewMetadata => 'View Metadata'; + + @override + String get viewOnboarding => 'View Onboarding'; + + @override + String get viewQueue => 'View queue'; + + @override + String get visualizer => 'Visualizer'; + + @override + String get visualizerAlbumColorsDescription => + 'Follow the album cover colors; monochrome when unavailable'; + + @override + String get visualizerBlocks => 'Fading Blocks'; + + @override + String get visualizerBlocksDescription => + 'Segmented bars with softly fading trails'; + + @override + String get visualizerColors => 'Colors'; + + @override + String get visualizerMonochrome => 'Monochrome'; + + @override + String get visualizerMonochromeDescription => + 'White and gray, independent of the album cover'; + + @override + String get visualizerRainbow => 'Rainbow'; + + @override + String get visualizerRainbowDescription => + 'A spectrum of colors across the visualizer'; + + @override + String get visuals => 'Visuals'; + + @override + String get volume => 'Volume'; + + @override + String get volumeControl => 'Volume Control'; + + @override + String get volumeDipsWhileNotificationSoundsPlay => + 'Volume dips while notification sounds play'; + + @override + String get volumeIsFixedWhileBitPerfect => + 'Volume is fixed while bit-perfect passthrough is active and this DAC has no hardware volume control.'; + + @override + String get volumeIsFixedWhileBitPerfect2 => + 'Volume is fixed while bit-perfect passthrough is active: the stream is sent untouched and this DAC has no hardware volume control.'; + + @override + String wAgo(Object arg1) { + return '${arg1}w ago'; + } + + @override + String get waitingForBrowserAuthorization => + 'Waiting for browser authorization...'; + + @override + String get waitingForPlayback => 'Waiting for playback'; + + @override + String get wantEveryControlDocumentedOpenThe => + 'Want every control documented? Open the in-app Manual anytime from Settings → Help & Manual.'; + + @override + String was(Object arg1) { + return 'was: $arg1'; + } + + @override + String get wave => 'Wave'; + + @override + String get waveform => 'Waveform'; + + @override + String weLlKeepTheBestQuality(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count copies', + one: '$count copy', + ); + return 'We’ll keep the best-quality version in each group (prefers album art, then highest bitrate) and remove $_temp0. Files on disk are not deleted.'; + } + + @override + String weLlKeepYourCheckedVersion(int kept, int removed) { + String _temp0 = intl.Intl.pluralLogic( + kept, + locale: localeName, + other: '$kept checked versions', + one: '$kept checked version', + ); + String _temp1 = intl.Intl.pluralLogic( + removed, + locale: localeName, + other: '$removed copies', + one: '$removed copy', + ); + return 'We’ll keep your $_temp0 and remove the other $_temp1 from your library. Audio files on disk are not deleted.'; + } + + @override + String get webdav => 'WebDAV'; + + @override + String get weekly => 'Weekly'; + + @override + String get welcomeBackLetSStartA => 'Welcome back — let\'s start a streak.'; + + @override + String get welcomeToFlick => 'Welcome to Flick!'; + + @override + String get welcomeToFlick2 => 'Welcome to Flick'; + + @override + String get whatSNew => 'What\'s New'; + + @override + String get whenYouPlayOverBluetoothAndroid => + 'When you play over Bluetooth, Android negotiates the codec with your headphones or speaker.'; + + @override + String get whereShouldTheLrcFileBe => 'Where should the .lrc file be saved?'; + + @override + String get whereTheFocalSongSitsVertically => + 'Where the focal song sits vertically'; + + @override + String get whereYourMoneyGoes => 'Where Your Money Goes'; + + @override + String get whisperWorld => 'Whisper World'; + + @override + String get whisperedSecrets => 'Whispered Secrets'; + + @override + String get white => 'White'; + + @override + String get wholeAlbum => 'Whole album'; + + @override + String get whyDonate => 'Why Donate'; + + @override + String wide(Object amount) { + return '$amount% wide'; + } + + @override + String get widgets => 'Widgets'; + + @override + String get width => 'Width'; + + @override + String get wildWeather => 'Wild Weather'; + + @override + String get willBeRemoved => 'Will be removed'; + + @override + String get willKeep => 'Will keep'; + + @override + String get wiredOutput => 'Wired output'; + + @override + String word(Object arg1, Object arg2) { + return 'Word $arg1 · \"$arg2\"'; + } + + @override + String word2(Object arg1, Object token) { + return 'Word $arg1 · \"$token\"'; + } + + @override + String get wordSync => 'Word Sync'; + + @override + String get wordSyncModeKaraoke => 'Word Sync mode (karaoke)'; + + @override + String wordTimelineLine(Object arg1) { + return 'Word Timeline · Line $arg1'; + } + + @override + String get wrapAroundAndQueueBehavior => 'Wrap-around and queue behavior'; + + @override + String get wrapAroundQueue => 'Wrap-around Queue'; + + @override + String get writeADescription => 'Write a description'; + + @override + String x(Object min) { + return '${min}x'; + } + + @override + String x2(Object max) { + return '${max}x'; + } + + @override + String x3(Object currentSpeed) { + return '${currentSpeed}x'; + } + + @override + String yAgo(Object arg1) { + return '${arg1}y ago'; + } + + @override + String get year => 'Year'; + + @override + String get yearly => 'Yearly'; + + @override + String get yesterday => 'Yesterday'; + + @override + String get youAlreadyHaveTheLatestFlick => + 'You already have the latest Flick release'; + + @override + String get youAlreadyHaveTheLatestPlay => + 'You already have the latest Play Store release'; + + @override + String get youCanAlsoChangeTheCodec => + 'You can also change the codec in Android Developer Options under \"Bluetooth Audio Codec\".'; + + @override + String get youCustomizedWhichVersionsToKeep => + 'You customized which versions to keep. Nice — you\'re in control.'; + + @override + String get youHaveUnsavedChangesAreYou => + 'You have unsaved changes. Are you sure you want to discard them?'; + + @override + String get youHaveUnsavedLyricEditsLeave => + 'You have unsaved lyric edits. Leave the Sync Studio without saving?'; + + @override + String get youReOffline => 'You\'re offline'; + + @override + String get youReOfflineSomeOnlineFeatures => + 'You\'re offline. Some online features may not work.'; + + @override + String get youVeHitTheThresholdKeep => + 'You\'ve hit the threshold — keep it up!'; + + @override + String get yourCollectionAtAGlance => 'Your collection at a glance'; + + @override + String get yourCustomCollections => 'Your custom collections'; + + @override + String get yourHeaviestRotationRightNow => 'Your heaviest rotation right now'; + + @override + String get yourLatestLibraryScans => 'Your latest library scans'; + + @override + String get yourLibrary => 'Your Library'; + + @override + String get yourLibraryAtAGlance => 'Your library at a glance'; + + @override + String get yourLibraryIsTidyWeLl => + 'Your library is tidy. We’ll let you know if new duplicates appear after the next scan.'; + + @override + String get yourListeningHistoryIsStillYours => + 'Your listening history is still yours. Try loading it again.'; + + @override + String get yourListensWillRemainOnListenbrainz => + 'Your listens will remain on ListenBrainz, but Flick will stop submitting them.'; + + @override + String get yourLogsAreUploadedToDpaste => + 'Your logs are uploaded to dpaste.com as an unlisted link that expires in 30 days. Anyone you share the link with can read them — logs may contain file paths and device details.'; + + @override + String get yourMonthlyRecapNeedsABit => + 'Your monthly recap needs a bit more listening time this month.'; + + @override + String get yourMostReplayedTrack => 'Your most replayed track'; + + @override + String get yourMusicIsBeingScrobbled => 'Your music is being scrobbled'; + + @override + String get yourMusicIsBeingSubmitted => 'Your music is being submitted'; + + @override + String get yourMusicOnRepeat => 'Your music. On repeat.'; + + @override + String get yourNewAudioEngineIsReady => + 'Your new audio engine is ready. Restart Flick to apply it.'; + + @override + String get yourNextFavoriteIsWaiting => 'Your next favorite is waiting.'; + + @override + String get yourNextFavoriteNisWaiting => 'Your next favorite\nis waiting.'; + + @override + String get yourPlaylists => 'Your Playlists'; + + @override + String get yourScrobblingHistoryWillRemainOn => + 'Your scrobbling history will remain on Last.fm, but Flick will stop sending scrobbles.'; + + @override + String get yourSessionHistory => 'Your session history'; + + @override + String get yourWeeklyRecapAppearsOnceYou => + 'Your weekly recap appears once you start listening this week.'; + + @override + String get yourWholeLibraryLivesHereTap => + 'Your whole library lives here. Tap any song to play it.'; + + @override + String get yourYearlyRecapFillsInAs => + 'Your yearly recap fills in as you keep listening throughout the year.'; +} + +/// The translations for Tagalog, using the Tagalog Baybayin Alibata script (`tl_Tglg`). +class AppLocalizationsTlTglg extends AppLocalizationsTl { + AppLocalizationsTlTglg() : super('tl_Tglg'); + + @override + String get addToQueue => 'ᜁᜇᜄ᜔ᜇᜄ᜔ ᜐ ᜉᜒᜎ'; + + @override + String get album => 'ᜀᜎ᜔ᜊᜓᜋ᜔'; + + @override + String get albums => 'ᜋᜅ ᜀᜎ᜔ᜊᜓᜋ᜔'; + + @override + String get allSongs => 'ᜎᜑᜆ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ'; + + @override + String get artist => 'ᜃᜓᜋᜈ᜔ᜆ'; + + @override + String get artists => 'ᜋᜅ ᜃᜓᜋᜈ᜔ᜆ'; + + @override + String get back => 'ᜊᜓᜋᜎᜒᜃ᜔'; + + @override + String get cancel => 'ᜃᜈ᜔ᜐᜒᜎᜑᜒᜈ᜔'; + + @override + String get close => 'ᜁᜐᜇ'; + + @override + String get delete => 'ᜊᜓᜇᜑᜒᜈ᜔'; + + @override + String get deselectAll => 'ᜀᜎᜒᜐᜒᜈ᜔ ᜎᜑᜆ᜔ ᜈᜅ᜔ ᜉᜒᜈᜒᜎᜒ'; + + @override + String get done => 'ᜆᜉᜓᜐ᜔'; + + @override + String get favorites => 'ᜋᜅ ᜉᜊᜓᜇᜒᜆᜓ'; + + @override + String get folder => 'ᜉᜓᜎ᜔ᜇᜒᜇ᜔'; + + @override + String get folders => 'ᜋᜅ ᜉᜓᜎ᜔ᜇᜒᜇ᜔'; + + @override + String get interfaceLabel => 'ᜁᜆ᜔ᜐᜓᜇ'; + + @override + String get language => 'ᜏᜒᜃ'; + + @override + String get languageSectionDescription => + 'ᜉᜒᜎᜒᜁᜈ᜔ ᜀᜅ᜔ ᜏᜒᜃᜅ᜔ ᜄᜄᜋᜒᜆᜒᜈ᜔ ᜐ ᜀᜉ᜔ᜎᜒᜃᜐ᜔ᜌᜓᜈ᜔.'; + + @override + String get languageSystemDefault => 'ᜏᜒᜃ ᜈᜅ᜔ ᜀᜉᜇᜆᜓ'; + + @override + String get lyrics => 'ᜎᜒᜇᜒᜃ'; + + @override + String get menu => 'ᜆᜎᜀᜈ᜔'; + + @override + String get next => 'ᜐᜓᜐᜓᜈᜓᜇ᜔'; + + @override + String get nextSong => 'ᜐᜓᜐᜓᜈᜓᜇ᜔ ᜈ ᜃᜈ᜔ᜆ'; + + @override + String get noSongsFound => 'ᜏᜎᜅ᜔ ᜈᜑᜈᜉ᜔ ᜈ ᜃᜈ᜔ᜆ'; + + @override + String get nowPlaying => 'ᜃᜐᜎᜓᜃᜓᜌᜅ᜔ ᜆᜓᜋᜓᜆᜓᜄ᜔ᜆᜓᜄ᜔'; + + @override + String get off => 'ᜉᜆᜌ᜔'; + + @override + String get pause => 'ᜁᜑᜒᜈ᜔ᜆᜓ ᜋᜓᜈ'; + + @override + String get play => 'ᜉᜆᜓᜄ᜔ᜆᜓᜄᜒᜈ᜔'; + + @override + String get playNext => 'ᜁᜐᜓᜈᜓᜇ᜔'; + + @override + String get playlist2 => 'ᜆᜎᜀᜈ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ'; + + @override + String get playlists => 'ᜋᜅ ᜆᜎᜀᜈ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ'; + + @override + String get previousSong => 'ᜈᜃᜇᜀᜅ᜔ ᜃᜈ᜔ᜆ'; + + @override + String get previousSong2 => 'ᜈᜃᜇᜀᜅ᜔ ᜃᜈ᜔ᜆ'; + + @override + String get queue => 'ᜉᜒᜎ'; + + @override + String get remove => 'ᜀᜎᜒᜐᜒᜈ᜔'; + + @override + String repeat(Object arg1) { + return 'ᜂᜎᜒᜆ᜔: $arg1'; + } + + @override + String get repeatMode => 'ᜉᜇᜀᜈ᜔ ᜈᜅ᜔ ᜉᜄ᜔-ᜂᜎᜒᜆ᜔'; + + @override + String get search => 'ᜑᜈᜉᜒᜈ᜔'; + + @override + String get selectAll => 'ᜉᜒᜎᜒᜁᜈ᜔ ᜎᜑᜆ᜔'; + + @override + String get settings => 'ᜋᜅ ᜉᜄ᜔ᜐᜐᜀᜌᜓᜐ᜔'; + + @override + String get share => 'ᜁᜊᜑᜄᜒ'; + + @override + String get shuffle => 'ᜁᜑᜎᜓ'; + + @override + String shuffle2(Object arg1) { + return 'ᜉᜄ᜔ᜑᜎᜓ: $arg1'; + } + + @override + String get shuffleMode => 'ᜉᜇᜀᜈ᜔ ᜈᜅ᜔ ᜉᜄ᜔ᜑᜎᜓ'; + + @override + String songs(Object arg1, Object arg2) { + return '$arg1 • $arg2 ᜃᜈ᜔ᜆ'; + } + + @override + String get songs14 => 'ᜋᜅ ᜃᜈ᜔ᜆ'; + + @override + String songsCount(int count) { + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count ᜃᜈ᜔ᜆ', + one: '$count ᜃᜈ᜔ᜆ', + ); + return '$_temp0'; + } + + @override + String get stop => 'ᜁᜑᜒᜈ᜔ᜆᜓ'; + + @override + String tracks(Object _totalTracks) { + return '$_totalTracks ᜃᜈ᜔ᜆ'; + } + + @override + String get volume => 'ᜎᜃᜐ᜔ ᜈᜅ᜔ ᜆᜓᜈᜓᜄ᜔'; +} diff --git a/pubspec.yaml b/pubspec.yaml index ef4b75b2..9c6d8449 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -128,6 +128,7 @@ flutter: - assets/autoeq/autoeq_brands.json - assets/fonts/GoogleSansFlex-OFL.txt - assets/fonts/NotoSansSC-OFL.txt + - assets/fonts/NotoSansTagalog-OFL.txt fonts: # Google Sans Flex replaces Product Sans, which was not licensed for @@ -176,3 +177,11 @@ flutter: - asset: assets/fonts/NotoSansSC-Bold.ttf weight: 700 style: normal + + # Full, unmodified OFL font (~52 KB), including both vowel-cancelling marks. + # Explicitly requested by AppTheme.fontFamilyFallback, including in Latin UI + # so the language selector can display Baybayin before it is selected. + - family: NotoSansTagalog + fonts: + - asset: assets/fonts/NotoSansTagalog-Regular.ttf + weight: 400 diff --git a/test/l10n/baybayin_layout_test.dart b/test/l10n/baybayin_layout_test.dart new file mode 100644 index 00000000..e5553c29 --- /dev/null +++ b/test/l10n/baybayin_layout_test.dart @@ -0,0 +1,246 @@ +// Real bundled fonts and layout assertions, not platform-dependent pixel goldens. +// Enable BAYBAYIN_SCREENSHOTS for images a human can review for mark placement. +import 'dart:io'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'package:flick/core/theme/app_theme.dart'; +import 'package:flick/features/settings/widgets/language_settings_card.dart'; +import 'package:flick/features/settings/widgets/settings_widgets.dart'; +import 'package:flick/l10n/l10n.dart'; +import 'package:flick/models/mini_player_config.dart'; +import 'package:flick/models/nav_bar_config.dart'; +import 'package:flick/widgets/common/mini_player_bar.dart'; +import 'package:flick/widgets/navigation/flick_nav_bar.dart'; + +const _shotKey = ValueKey('baybayin_layout_shot'); +const _screenshots = bool.fromEnvironment('BAYBAYIN_SCREENSHOTS'); + +Future _shoot(WidgetTester tester, String name) async { + if (!_screenshots) return; + final boundary = tester.renderObject( + find.byKey(_shotKey), + ); + await tester.runAsync(() async { + final image = await boundary.toImage(pixelRatio: 2); + try { + final bytes = await image.toByteData(format: ui.ImageByteFormat.png); + final file = File('build/baybayin_shots/$name.png'); + await file.parent.create(recursive: true); + await file.writeAsBytes(bytes!.buffer.asUint8List()); + } finally { + image.dispose(); + } + }); +} + +Widget _app(Widget child, {double scale = 1}) => ProviderScope( + child: RepaintBoundary( + key: _shotKey, + child: ValueListenableBuilder( + valueListenable: LocaleController.instance, + builder: (context, selectedLocale, _) => MaterialApp( + debugShowCheckedModeBanner: false, + theme: AppTheme.darkTheme, + locale: selectedLocale, + supportedLocales: kSupportedLocales, + localizationsDelegates: kAppLocalizationsDelegates, + localeResolutionCallback: resolveAppLocale, + builder: (context, child) { + LocaleController.instance.bind(AppLocalizations.of(context)); + return MediaQuery( + data: MediaQuery.of(context).copyWith( + textScaler: TextScaler.linear(scale), + disableAnimations: true, + ), + child: child!, + ); + }, + home: Scaffold(body: child), + ), + ), + ), +); + +Widget _languagePage() => SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Builder( + builder: (context) => SettingsSectionHeader(context.l10n.language), + ), + const LanguageSettingsCard(), + ], + ), +); + +Finder _option(String autonym) => find.byWidgetPredicate( + (widget) => widget is SelectionSetting && widget.title == autonym, +); + +void _setSize(WidgetTester tester, double width) { + tester.view.devicePixelRatio = 1; + tester.view.physicalSize = Size(width, 900); +} + +void main() { + setUpAll(() async { + TestWidgetsFlutterBinding.ensureInitialized(); + await (FontLoader('GoogleSansFlex') + ..addFont(rootBundle.load('assets/fonts/GoogleSansFlex-Regular.ttf')) + ..addFont(rootBundle.load('assets/fonts/GoogleSansFlex-Bold.ttf'))) + .load(); + await (FontLoader('NotoSansSC') + ..addFont(rootBundle.load('assets/fonts/NotoSansSC-Regular.ttf')) + ..addFont(rootBundle.load('assets/fonts/NotoSansSC-Bold.ttf'))) + .load(); + await (FontLoader( + 'NotoSansTagalog', + )..addFont(rootBundle.load('assets/fonts/NotoSansTagalog-Regular.ttf'))) + .load(); + await (FontLoader( + 'MaterialIcons', + )..addFont(rootBundle.load('fonts/MaterialIcons-Regular.otf'))).load(); + await (FontLoader('packages/lucide_icons_flutter/Lucide')..addFont( + rootBundle.load('packages/lucide_icons_flutter/assets/lucide.ttf'), + )) + .load(); + }); + + setUp(() { + SharedPreferences.setMockInitialValues({}); + }); + + tearDown(() { + LocaleController.instance.value = null; + LocaleController.instance.bindLocale(kFallbackLocale); + }); + + testWidgets('language choices survive narrow screens and enlarged text', ( + tester, + ) async { + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + for (final locale in kSupportedLocales) { + for (final width in [320.0, 375.0, 600.0]) { + for (final scale in [1.0, 2.0, 3.0]) { + _setSize(tester, width); + LocaleController.instance.value = locale; + // Reset the page/scroll position between sweep cases. + await tester.pumpWidget(const SizedBox()); + await tester.pumpWidget(_app(_languagePage(), scale: scale)); + await tester.pumpAndSettle(); + expect( + tester.takeException(), + isNull, + reason: '$locale width=$width scale=$scale', + ); + expect(_option('Tagalog (Baybayin)'), findsOneWidget); + expect(_option('English'), findsOneWidget); + if (width == 320 && scale == 1 && locale.languageCode != 'zh') { + await _shoot(tester, 'language-${locale.toString()}-320'); + } + await tester.ensureVisible(_option('English')); + await tester.pumpAndSettle(); + expect( + _option('English').hitTestable(), + findsOneWidget, + reason: 'The escape option must remain reachable.', + ); + expect(tester.takeException(), isNull); + } + } + } + }); + + testWidgets('the actual selector can enter Baybayin and escape to English', ( + tester, + ) async { + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + _setSize(tester, 320); + LocaleController.instance.value = const Locale('en'); + await tester.pumpWidget(_app(_languagePage(), scale: 2)); + await tester.pumpAndSettle(); + await tester.ensureVisible(_option('Tagalog (Baybayin)')); + await tester.tap(_option('Tagalog (Baybayin)')); + await tester.pumpAndSettle(); + expect(LocaleController.instance.value, kBaybayinLocale); + expect( + tester.widget(_option('Tagalog (Baybayin)')).selected, + isTrue, + ); + expect(l10n.language, 'ᜏᜒᜃ'); + await tester.ensureVisible(_option('English')); + await tester.pumpAndSettle(); + await _shoot(tester, 'language-tl_Tglg-320-large-escape'); + await tester.tap(_option('English')); + await tester.pumpAndSettle(); + expect(LocaleController.instance.value, const Locale('en')); + expect(l10n.language, 'Language'); + expect(tester.takeException(), isNull); + }); + + testWidgets('Baybayin navigation fits without changing music metadata', ( + tester, + ) async { + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + LocaleController.instance.value = kBaybayinLocale; + for (final width in [320.0, 375.0, 600.0]) { + for (final scale in [1.0, 2.0, 3.0]) { + for (final allButtons in [false, true]) { + _setSize(tester, width); + await tester.pumpWidget( + _app( + Align( + alignment: Alignment.bottomCenter, + child: FlickNavBar( + config: allButtons + ? NavBarConfig( + enabledButtons: NavBarButton.values, + showLabels: true, + ) + : NavBarConfig.defaultConfig, + currentIndex: 1, + onTap: (_) {}, + showMiniPlayer: true, + miniPlayerWidget: MiniPlayerBar( + config: MiniPlayerConfig.defaultConfig, + songId: 'test-song', + title: 'Jóga', + artist: 'Björk', + progress: 0.42, + enableHero: false, + onPlayPause: () {}, + onPrevious: () {}, + onNext: () {}, + ), + ), + ), + scale: scale, + ), + ); + await tester.pumpAndSettle(); + expect( + tester.takeException(), + isNull, + reason: 'width=$width scale=$scale allButtons=$allButtons', + ); + expect(find.text('Jóga'), findsOneWidget); + expect(find.text('Björk'), findsOneWidget); + if (width == 375 && scale == 1 && !allButtons) { + await _shoot(tester, 'navigation-tl_Tglg-375'); + } + } + } + } + }); +} diff --git a/test/l10n/baybayin_pilot_test.dart b/test/l10n/baybayin_pilot_test.dart new file mode 100644 index 00000000..b5027ddf --- /dev/null +++ b/test/l10n/baybayin_pilot_test.dart @@ -0,0 +1,174 @@ +// Technical checks do not certify the Tagalog wording or Baybayin spelling. +// Human approval is recorded separately in the review sheet and ARB metadata. +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flick/core/theme/app_theme.dart'; +import 'package:flick/l10n/l10n.dart'; + +Map _arb(String name) => + jsonDecode(File('lib/l10n/$name.arb').readAsStringSync()) + as Map; + +Map _messages(Map arb) => { + for (final entry in arb.entries) + if (!entry.key.startsWith('@')) entry.key: entry.value as String, +}; + +Set _placeholders(String message) => RegExp( + r'\{([A-Za-z_]\w*)\s*[,}]', +).allMatches(message).map((match) => match.group(1)!).toSet(); + +/// Actual nonzero cmap format-4 glyph mappings, not just segment ranges (which +/// can contain holes). All Tagalog characters are in the BMP. No font-tool dep. +Set _fontCodepoints(ByteData data) { + int u16(int offset) => data.getUint16(offset); + int u32(int offset) => data.getUint32(offset); + for (var table = 0; table < u16(4); table++) { + final record = 12 + table * 16; + if (u32(record) != 0x636d6170) continue; // cmap + final cmap = u32(record + 8); + final result = {}; + for (var subtable = 0; subtable < u16(cmap + 2); subtable++) { + final offset = cmap + u32(cmap + 4 + subtable * 8 + 4); + if (u16(offset) != 4) continue; + final segments = u16(offset + 6) ~/ 2; + final ends = offset + 14; + final starts = ends + segments * 2 + 2; + final deltas = starts + segments * 2; + final ranges = deltas + segments * 2; + for (var segment = 0; segment < segments; segment++) { + final start = u16(starts + segment * 2); + final end = u16(ends + segment * 2); + final delta = data.getInt16(deltas + segment * 2); + final rangeAddress = ranges + segment * 2; + final range = u16(rangeAddress); + for (var char = start; char <= end && char < 0xffff; char++) { + var glyph = range == 0 + ? char + : u16(rangeAddress + range + (char - start) * 2); + if (range == 0 || glyph != 0) glyph = (glyph + delta) & 0xffff; + if (glyph != 0) result.add(char); + } + } + } + return result; + } + throw StateError('Bundled font has no cmap table'); +} + +void main() { + final en = _messages(_arb('app_en')); + final arb = _arb('app_tl_Tglg'); + final pilot = _messages(arb); + + test('the partial pilot is explicit and every draft has review context', () { + expect(arb['@@locale'], 'tl_Tglg'); + expect(pilot.length, inInclusiveRange(40, 60)); + expect( + _messages(_arb('app_tl')), + isEmpty, + reason: + 'Generator-only base must keep English fallback, not Latin Tagalog.', + ); + expect(pilot.keys.toSet().difference(en.keys.toSet()), isEmpty); + final review = File('docs/BAYBAYIN_REVIEW.md').readAsStringSync(); + for (final entry in pilot.entries) { + final metadata = arb['@${entry.key}'] as Map; + expect(metadata['description'], isNotEmpty, reason: entry.key); + expect(metadata['x-latin'], isNotEmpty, reason: entry.key); + expect( + metadata['x-review-status'], + isIn(['draft', 'needs-change', 'approved']), + ); + expect( + review, + contains( + '| `${entry.key}` | ${en[entry.key]} | ${metadata['description']} ' + '| ${metadata['x-latin']} | ${entry.value} | ${metadata['x-review-status']} |', + ), + reason: 'Keep the review row in sync with ${entry.key}.', + ); + } + }); + + test('both scripts preserve every source placeholder', () { + for (final entry in pilot.entries) { + final latin = + (arb['@${entry.key}'] as Map)['x-latin'] as String; + expect( + _placeholders(entry.value), + _placeholders(en[entry.key]!), + reason: entry.key, + ); + expect( + _placeholders(latin), + _placeholders(en[entry.key]!), + reason: entry.key, + ); + } + }); + + test('reviewer corrections reach the pilot labels and related forms', () { + final strings = lookupFlickLocalizations(kBaybayinLocale); + expect(strings.songs14, 'ᜋᜅ ᜃᜈ᜔ᜆ'); + expect(strings.artists, 'ᜋᜅ ᜃᜓᜋᜈ᜔ᜆ'); + expect(strings.artist, 'ᜃᜓᜋᜈ᜔ᜆ'); + expect(strings.playlists, 'ᜋᜅ ᜆᜎᜀᜈ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ'); + expect(strings.playlist2, 'ᜆᜎᜀᜈ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ'); + expect(strings.nextSong, 'ᜐᜓᜐᜓᜈᜓᜇ᜔ ᜈ ᜃᜈ᜔ᜆ'); + expect(strings.previousSong, 'ᜈᜃᜇᜀᜅ᜔ ᜃᜈ᜔ᜆ'); + expect(strings.previousSong2, strings.previousSong); + expect(strings.lyrics, 'ᜎᜒᜇᜒᜃ'); + expect(strings.allSongs, 'ᜎᜑᜆ᜔ ᜈᜅ᜔ ᜃᜈ᜔ᜆ'); + expect(strings.noSongsFound, 'ᜏᜎᜅ᜔ ᜈᜑᜈᜉ᜔ ᜈ ᜃᜈ᜔ᜆ'); + // The correction is for Next song, not onboarding's separate Next label. + expect(strings.next, 'ᜐᜓᜐᜓᜈᜓᜇ᜔'); + }); + + test('translated and fallback plurals and arguments survive generation', () { + final strings = lookupFlickLocalizations(kBaybayinLocale); + for (final count in [0, 1, 2, 101]) { + expect(strings.songsCount(count), '$count ᜃᜈ᜔ᜆ'); + expect(strings.tracks(count), '$count ᜃᜈ᜔ᜆ'); + expect(strings.songUnit(count), count == 1 ? 'song' : 'songs'); + } + expect(strings.songs('3:25', 7), '3:25 • 7 ᜃᜈ᜔ᜆ'); + expect(strings.repeat('MODE'), 'ᜂᜎᜒᜆ᜔: MODE'); + expect(strings.shuffle2('MODE'), 'ᜉᜄ᜔ᜑᜎᜓ: MODE'); + expect(strings.baybayinPilotDescription, en['baybayinPilotDescription']); + expect(strings.flickReplay, en['flickReplay']); + expect(strings.unknownArtist, en['unknownArtist']); + }); + + test( + 'the bundled fallback covers the script and its combining/final marks', + () { + final bytes = File( + 'assets/fonts/NotoSansTagalog-Regular.ttf', + ).readAsBytesSync(); + final supported = _fontCodepoints(ByteData.sublistView(bytes)); + final required = { + // Complete modern Tagalog alphabet, not just this pilot's current glyphs. + for (var char = 0x1700; char <= 0x1715; char++) char, + 0x171f, // archaic ra + 0x1735, 0x1736, // Philippine punctuation + for (final message in pilot.values) + ...message.runes.where((char) => char >= 0x1700 && char <= 0x1736), + }; + expect(required.difference(supported), isEmpty); + expect(AppTheme.fontFamilyFallback, contains('NotoSansTagalog')); + expect( + AppTheme.darkTheme.textTheme.bodyMedium!.fontFamilyFallback, + contains('NotoSansTagalog'), + ); + expect( + File('assets/fonts/NotoSansTagalog-OFL.txt').readAsStringSync(), + contains('SIL OPEN FONT LICENSE Version 1.1'), + ); + }, + ); +} diff --git a/test/l10n/locale_switch_test.dart b/test/l10n/locale_switch_test.dart index 0d900941..ccc35eb9 100644 --- a/test/l10n/locale_switch_test.dart +++ b/test/l10n/locale_switch_test.dart @@ -18,6 +18,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flick/l10n/l10n.dart'; +import 'package:flick/services/app_preferences_service.dart'; /// The same wiring `lib/app/app.dart` uses: the controller drives `locale`, and /// the builder keeps the global accessor pointed at the active localizations. @@ -26,15 +27,21 @@ Widget _app() { valueListenable: LocaleController.instance, builder: (context, selectedLocale, _) { return MaterialApp( - localizationsDelegates: AppLocalizations.localizationsDelegates, + localizationsDelegates: kAppLocalizationsDelegates, supportedLocales: kSupportedLocales, + localeResolutionCallback: resolveAppLocale, locale: selectedLocale, home: Builder( builder: (context) { LocaleController.instance.bind(AppLocalizations.of(context)); // Read through the global accessor on purpose: this is what the // service layer and the enumerated labels do. - return Text(l10n.flickReplay, textDirection: TextDirection.ltr); + return Column( + children: [ + Text(l10n.flickReplay), + Text(l10n.language), + ], + ); }, ), ); @@ -52,6 +59,7 @@ void main() { tearDown(() { // Singleton: leave it following the device locale for the next test. LocaleController.instance.value = null; + LocaleController.instance.bindLocale(kFallbackLocale); }); testWidgets('a language switch reaches the global l10n accessor', (tester) async { @@ -84,4 +92,139 @@ void main() { expect(l10n.flickReplay, 'Flick Replay'); expect(find.text('Flick Replay'), findsOneWidget); }); + + test('script-specific locales are never matched by language alone', () { + const cases = <(Locale, Locale)>[ + (Locale('en', 'GB'), Locale('en')), + (Locale('zh', 'TW'), Locale('zh', 'CN')), + (Locale('tl'), kFallbackLocale), + (Locale('tl', 'PH'), kFallbackLocale), + (Locale('fil', 'PH'), kFallbackLocale), + ( + Locale.fromSubtags(languageCode: 'tl', scriptCode: 'Latn'), + kFallbackLocale, + ), + ( + Locale.fromSubtags( + languageCode: 'tl', + scriptCode: 'Tglg', + countryCode: 'PH', + ), + kBaybayinLocale, + ), + (Locale('es'), kFallbackLocale), + ]; + for (final (requested, expected) in cases) { + expect(resolveSupportedLocale(requested), expected); + expect(resolveAppLocale(requested, kSupportedLocales), expected); + } + expect(kSupportedLocales, isNot(contains(const Locale('tl')))); + }); + + test('Baybayin retains its script across a persisted reload', () async { + final controller = LocaleController.instance; + await controller.select(kBaybayinLocale); + expect(await AppPreferencesService().getAppLocale(), 'tl_Tglg'); + + // Simulate startup: forget the in-memory selection, then load preferences. + controller.value = null; + await controller.load(); + expect(controller.value, kBaybayinLocale); + controller.bindLocale(controller.effectiveLocale); + expect(l10n.language, 'ᜏᜒᜃ'); + + await controller.select(null); + expect(await AppPreferencesService().getAppLocale(), 'system'); + controller.value = kBaybayinLocale; + await controller.load(); + expect(controller.followsSystem, isTrue); + }); + + test('stored legacy, script/region and malformed tags resolve safely', () async { + const cases = { + 'en': Locale('en'), + 'en_US': Locale('en'), + 'zh_CN': Locale('zh', 'CN'), + 'zh_TW': Locale('zh', 'CN'), + 'tl_Tglg': kBaybayinLocale, + 'tl-Tglg-PH': kBaybayinLocale, + 'TL_tglg_ph': kBaybayinLocale, + 'tl_PH': kFallbackLocale, + 'tl_Latn_PH': kFallbackLocale, + 'fil': kFallbackLocale, + 'tl_Tglg_broken': kFallbackLocale, + '_Tglg': kFallbackLocale, + 'system': null, + '': null, + }; + for (final entry in cases.entries) { + await AppPreferencesService().setAppLocale(entry.key); + await LocaleController.instance.load(); + expect(LocaleController.instance.value, entry.value, reason: entry.key); + } + }); + + testWidgets('ordinary Filipino device locales do not activate Baybayin', ( + tester, + ) async { + final dispatcher = tester.binding.platformDispatcher; + addTearDown(dispatcher.clearLocalesTestValue); + for (final deviceLocale in [ + const Locale('tl'), + const Locale('tl', 'PH'), + const Locale('fil', 'PH'), + const Locale.fromSubtags(languageCode: 'tl', scriptCode: 'Latn'), + ]) { + dispatcher.localesTestValue = [deviceLocale]; + LocaleController.instance.value = null; + LocaleController.instance.bindLocale( + LocaleController.instance.effectiveLocale, + ); + expect(l10n.language, 'Language'); + await tester.pumpWidget(_app()); + await tester.pumpAndSettle(); + expect(l10n.localeName, 'en'); + expect(find.text('Language'), findsOneWidget); + expect( + Localizations.localeOf(tester.element(find.text('Language'))), + kFallbackLocale, + ); + } + }); + + testWidgets('English, Baybayin and Chinese switches reach widgets and services', ( + tester, + ) async { + await LocaleController.instance.select(const Locale('en')); + await tester.pumpWidget(_app()); + await LocaleController.instance.select(kBaybayinLocale); + await tester.pumpAndSettle(); + expect(l10n.language, 'ᜏᜒᜃ'); + expect(find.text('ᜏᜒᜃ'), findsOneWidget); + expect( + l10n.flickReplay, + 'Flick Replay', + reason: 'Intentional English fallback', + ); + final context = tester.element(find.text('ᜏᜒᜃ')); + expect(AppLocalizations.of(context).language, l10n.language); + expect( + l10n.songUnit(0), + 'songs', + reason: 'English fallback keeps English plurals.', + ); + expect(Localizations.localeOf(context), kBaybayinLocale); + expect(MaterialLocalizations.of(context).cancelButtonLabel, isNotEmpty); + expect(Directionality.of(context), TextDirection.ltr); + + await LocaleController.instance.select(const Locale('zh', 'CN')); + await tester.pumpAndSettle(); + expect(l10n.language, '语言'); + expect(find.text('语言'), findsOneWidget); + + await LocaleController.instance.select(const Locale('en')); + await tester.pumpAndSettle(); + expect(l10n.language, 'Language'); + expect(find.text('Language'), findsOneWidget); + }); }