feat: add translators section in about page and fix ARB locale format

This commit is contained in:
zarzet
2026-01-19 02:25:30 +07:00
parent 3c118f74e4
commit a650632c4e
19 changed files with 4280 additions and 24 deletions
+24
View File
@@ -107,6 +107,7 @@ abstract class AppLocalizations {
Locale('de'),
Locale('en'),
Locale('es'),
Locale('es', 'ES'),
Locale('fr'),
Locale('hi'),
Locale('id'),
@@ -114,6 +115,7 @@ abstract class AppLocalizations {
Locale('ko'),
Locale('nl'),
Locale('pt'),
Locale('pt', 'PT'),
Locale('ru'),
Locale('zh'),
Locale('zh', 'CN'),
@@ -816,6 +818,12 @@ abstract class AppLocalizations {
/// **'The talented artist who created our beautiful app logo!'**
String get aboutLogoArtist;
/// Section for translators
///
/// In en, this message translates to:
/// **'Translators'**
String get aboutTranslators;
/// Section for special thanks
///
/// In en, this message translates to:
@@ -3699,6 +3707,22 @@ class _AppLocalizationsDelegate
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when language+country codes are specified.
switch (locale.languageCode) {
case 'es':
{
switch (locale.countryCode) {
case 'ES':
return AppLocalizationsEsEs();
}
break;
}
case 'pt':
{
switch (locale.countryCode) {
case 'PT':
return AppLocalizationsPtPt();
}
break;
}
case 'zh':
{
switch (locale.countryCode) {
+22 -16
View File
@@ -115,7 +115,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get settingsTitle => 'Einstellungen';
@override
String get settingsDownload => 'Download';
String get settingsDownload => 'Herunterladen';
@override
String get settingsAppearance => 'Erscheinungsbild';
@@ -130,7 +130,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get settingsAbout => 'Über';
@override
String get downloadTitle => 'Download';
String get downloadTitle => 'Herunterladen';
@override
String get downloadLocation => 'Download-Speicherort';
@@ -410,40 +410,46 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get aboutLogoArtist =>
'The talented artist who created our beautiful app logo!';
'Der talentierte Künstler, der unser wunderschönes App-Logo entworfen hat!';
@override
String get aboutSpecialThanks => 'Special Thanks';
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Besonderer Dank';
@override
String get aboutLinks => 'Links';
@override
String get aboutMobileSource => 'Mobile source code';
String get aboutMobileSource => 'Mobiler Quellcode';
@override
String get aboutPCSource => 'PC source code';
String get aboutPCSource => 'PC Quellcode';
@override
String get aboutReportIssue => 'Report an issue';
String get aboutReportIssue => 'Problem melden';
@override
String get aboutReportIssueSubtitle => 'Report any problems you encounter';
String get aboutReportIssueSubtitle =>
'Melde jedes Problem, die dir auftreten';
@override
String get aboutFeatureRequest => 'Feature request';
String get aboutFeatureRequest => 'Feature vorschlagen';
@override
String get aboutFeatureRequestSubtitle => 'Suggest new features for the app';
String get aboutFeatureRequestSubtitle =>
'Schlage neue Funktionen für die App vor';
@override
String get aboutSupport => 'Support';
@override
String get aboutBuyMeCoffee => 'Buy me a coffee';
String get aboutBuyMeCoffee => 'Spendiere mir einen Kaffee';
@override
String get aboutBuyMeCoffeeSubtitle => 'Support development on Ko-fi';
String get aboutBuyMeCoffeeSubtitle =>
'Unterstütze die Entwicklung auf Ko-fi';
@override
String get aboutApp => 'App';
@@ -453,25 +459,25 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get aboutBinimumDesc =>
'The creator of QQDL & HiFi API. Without this API, Tidal downloads wouldn\'t exist!';
'Der Schöpfer der QQDL & HiFi API. Ohne diese API gäbe es keine Tidal-Downloads!';
@override
String get aboutSachinsenalDesc =>
'The original HiFi project creator. The foundation of Tidal integration!';
'Der ursprüngliche Entwickler des HiFi-Projekts. Die Grundlage der Tidal-Integration!';
@override
String get aboutDoubleDouble => 'DoubleDouble';
@override
String get aboutDoubleDoubleDesc =>
'Amazing API for Amazon Music downloads. Thank you for making it free!';
'Wundervolle API für Amazon Music Downloads.\nVielen Dank, dass Sie sie kostenlos zur Verfügung stellen!';
@override
String get aboutDabMusic => 'DAB Music';
@override
String get aboutDabMusicDesc =>
'The best Qobuz streaming API. Hi-Res downloads wouldn\'t be possible without this!';
'Die beste Qobuz-Streaming-API. Hi-Res-Downloads wären ohne diese nicht möglich!';
@override
String get aboutAppDescription =>
+3
View File
@@ -402,6 +402,9 @@ class AppLocalizationsEn extends AppLocalizations {
String get aboutLogoArtist =>
'The talented artist who created our beautiful app logo!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Special Thanks';
File diff suppressed because it is too large Load Diff
+3
View File
@@ -402,6 +402,9 @@ class AppLocalizationsFr extends AppLocalizations {
String get aboutLogoArtist =>
'The talented artist who created our beautiful app logo!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Special Thanks';
+3
View File
@@ -402,6 +402,9 @@ class AppLocalizationsHi extends AppLocalizations {
String get aboutLogoArtist =>
'The talented artist who created our beautiful app logo!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Special Thanks';
+3
View File
@@ -406,6 +406,9 @@ class AppLocalizationsId extends AppLocalizations {
String get aboutLogoArtist =>
'Seniman berbakat yang membuat logo aplikasi kita yang indah!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Terima Kasih Khusus';
+3
View File
@@ -402,6 +402,9 @@ class AppLocalizationsJa extends AppLocalizations {
String get aboutLogoArtist =>
'The talented artist who created our beautiful app logo!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'スペシャルサンクス';
+3
View File
@@ -402,6 +402,9 @@ class AppLocalizationsKo extends AppLocalizations {
String get aboutLogoArtist =>
'The talented artist who created our beautiful app logo!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Special Thanks';
+3
View File
@@ -402,6 +402,9 @@ class AppLocalizationsNl extends AppLocalizations {
String get aboutLogoArtist =>
'The talented artist who created our beautiful app logo!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Special Thanks';
File diff suppressed because it is too large Load Diff
+5 -2
View File
@@ -414,6 +414,9 @@ class AppLocalizationsRu extends AppLocalizations {
String get aboutLogoArtist =>
'Талантливый художник, который создал наш красивый логотип приложения!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Особая благодарность';
@@ -1533,7 +1536,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get trackFileInfo => 'Информация о файле';
@override
String get trackLyrics => 'Тексты песен';
String get trackLyrics => 'Текст песни';
@override
String get trackFileNotFound => 'Файл не найден';
@@ -1545,7 +1548,7 @@ class AppLocalizationsRu extends AppLocalizations {
String get trackOpenInSpotify => 'Открыть в Spotify';
@override
String get trackTrackName => 'Название трека';
String get trackTrackName => 'Название';
@override
String get trackArtist => 'Исполнитель';
+4 -1
View File
@@ -402,6 +402,9 @@ class AppLocalizationsZh extends AppLocalizations {
String get aboutLogoArtist =>
'The talented artist who created our beautiful app logo!';
@override
String get aboutTranslators => 'Translators';
@override
String get aboutSpecialThanks => 'Special Thanks';
@@ -4056,7 +4059,7 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
String get homeSupports => 'Supports: Track, Album, Playlist, Artist URLs';
@override
String get homeRecent => 'Recent';
String get homeRecent => '最新的';
@override
String get historyTitle => 'History';
+2
View File
@@ -290,6 +290,8 @@
"@aboutOriginalCreator": {"description": "Role description for original creator"},
"aboutLogoArtist": "The talented artist who created our beautiful app logo!",
"@aboutLogoArtist": {"description": "Role description for logo artist"},
"aboutTranslators": "Translators",
"@aboutTranslators": {"description": "Section for translators"},
"aboutSpecialThanks": "Special Thanks",
"@aboutSpecialThanks": {"description": "Section for special thanks"},
"aboutLinks": "Links",
+1 -1
View File
@@ -1,5 +1,5 @@
{
"@@locale": "es-ES",
"@@locale": "es_ES",
"@@last_modified": "2026-01-16",
"appName": "SpotiFLAC",
"@appName": {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"@@locale": "pt-PT",
"@@locale": "pt_PT",
"@@last_modified": "2026-01-16",
"appName": "SpotiFLAC",
"@appName": {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"@@locale": "zh-CN",
"@@locale": "zh_CN",
"@@last_modified": "2026-01-16",
"appName": "SpotiFLAC",
"@appName": {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"@@locale": "zh-TW",
"@@locale": "zh_TW",
"@@last_modified": "2026-01-16",
"appName": "SpotiFLAC",
"@appName": {
+150 -1
View File
@@ -86,6 +86,13 @@ class AboutPage extends StatelessWidget {
),
),
SliverToBoxAdapter(
child: SettingsSectionHeader(title: context.l10n.aboutTranslators),
),
const SliverToBoxAdapter(
child: _TranslatorsSection(),
),
SliverToBoxAdapter(
child: SettingsSectionHeader(title: context.l10n.aboutSpecialThanks),
),
@@ -395,7 +402,149 @@ class _ContributorItem extends StatelessWidget {
}
}
/// Settings item with 40x40 icon area to align with contributor avatars
/// Translator data model
class _Translator {
final String name;
final String githubUsername;
final String language;
final String flag;
const _Translator({
required this.name,
required this.githubUsername,
required this.language,
required this.flag,
});
}
/// Translators section with compact chip-style layout
class _TranslatorsSection extends StatelessWidget {
const _TranslatorsSection();
static const List<_Translator> _translators = [
_Translator(
name: 'Pedro Marcondes',
githubUsername: 'justapedro',
language: 'Portuguese',
flag: '🇵🇹',
),
_Translator(
name: 'Credits 125',
githubUsername: 'credits125',
language: 'Spanish',
flag: '🇪🇸',
),
_Translator(
name: 'Владислав',
githubUsername: 'OdiNoKiY_KoT',
language: 'Russian',
flag: '🇷🇺',
),
_Translator(
name: 'Max',
githubUsername: 'Amonoman',
language: 'German',
flag: '🇩🇪',
),
];
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
final cardColor = isDark
? Color.alphaBlend(Colors.white.withValues(alpha: 0.08), colorScheme.surface)
: colorScheme.surfaceContainerHighest;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Container(
decoration: BoxDecoration(
color: cardColor,
borderRadius: BorderRadius.circular(20),
),
padding: const EdgeInsets.all(16),
child: Wrap(
spacing: 8,
runSpacing: 8,
children: _translators.map((translator) => _TranslatorChip(
translator: translator,
)).toList(),
),
),
);
}
}
/// Individual translator chip
class _TranslatorChip extends StatelessWidget {
final _Translator translator;
const _TranslatorChip({required this.translator});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Material(
color: colorScheme.secondaryContainer,
borderRadius: BorderRadius.circular(20),
child: InkWell(
onTap: () => _launchGitHub(translator.githubUsername),
borderRadius: BorderRadius.circular(20),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: CachedNetworkImage(
imageUrl: 'https://github.com/${translator.githubUsername}.png',
width: 20,
height: 20,
fit: BoxFit.cover,
placeholder: (context, url) => Container(
width: 20,
height: 20,
color: colorScheme.surface,
child: Icon(Icons.person, size: 12, color: colorScheme.onSurfaceVariant),
),
errorWidget: (context, url, error) => Container(
width: 20,
height: 20,
color: colorScheme.surface,
child: Icon(Icons.person, size: 12, color: colorScheme.onSurfaceVariant),
),
),
),
const SizedBox(width: 8),
Text(
translator.name,
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: colorScheme.onSecondaryContainer,
fontWeight: FontWeight.w500,
),
),
const SizedBox(width: 6),
Text(
translator.flag,
style: const TextStyle(fontSize: 14),
),
],
),
),
),
);
}
Future<void> _launchGitHub(String username) async {
final uri = Uri.parse('https://github.com/$username');
await launchUrl(uri, mode: LaunchMode.inAppBrowserView);
}
}
class _AboutSettingsItem extends StatelessWidget {
final IconData icon;
final String title;