From d882fc292cff5be5f165153be65168a4c6f08eef Mon Sep 17 00:00:00 2001 From: zarzet Date: Tue, 30 Jun 2026 03:40:45 +0700 Subject: [PATCH] l10n: localize settings, store, and metadata UI strings Wire remaining hardcoded strings in about, download region picker, file organization settings, extension repo snackbars, release type badges, metadata queue actions, online cover labels, and update changelog fallback. --- lib/screens/artist_screen.dart | 4 +- lib/screens/repo_tab.dart | 11 ++- lib/screens/settings/about_page.dart | 4 +- .../settings/download_settings_page.dart | 80 +++++++++++-------- lib/screens/settings/files_settings_page.dart | 9 ++- lib/screens/track_metadata_edit_sheet.dart | 10 ++- lib/widgets/update_dialog.dart | 9 ++- 7 files changed, 75 insertions(+), 52 deletions(-) diff --git a/lib/screens/artist_screen.dart b/lib/screens/artist_screen.dart index 6dee6e2a..457a9ead 100644 --- a/lib/screens/artist_screen.dart +++ b/lib/screens/artist_screen.dart @@ -1967,7 +1967,9 @@ class _ArtistScreenState extends ConsumerState { borderRadius: BorderRadius.circular(4), ), child: Text( - album.albumType == 'ep' ? 'EP' : 'Single', + album.albumType == 'ep' + ? context.l10n.releaseTypeEp + : context.l10n.releaseTypeSingle, style: const TextStyle( color: Colors.white, fontSize: 10, diff --git a/lib/screens/repo_tab.dart b/lib/screens/repo_tab.dart index 8fef33b4..3de5b60c 100644 --- a/lib/screens/repo_tab.dart +++ b/lib/screens/repo_tab.dart @@ -608,8 +608,8 @@ class _RepoTabState extends ConsumerState { SnackBar( content: Text( success - ? '${ext.displayName} installed. Enable it in Settings > Extensions' - : 'Failed to install ${ext.displayName}', + ? context.l10n.snackbarExtensionInstalledEnable(ext.displayName) + : context.l10n.snackbarFailedToInstallNamed(ext.displayName), ), behavior: SnackBarBehavior.floating, ), @@ -629,8 +629,11 @@ class _RepoTabState extends ConsumerState { SnackBar( content: Text( success - ? '${ext.displayName} updated to v${ext.version}' - : 'Failed to update ${ext.displayName}', + ? context.l10n.snackbarExtensionUpdatedVersion( + ext.displayName, + ext.version, + ) + : context.l10n.snackbarFailedToUpdateNamed(ext.displayName), ), behavior: SnackBarBehavior.floating, ), diff --git a/lib/screens/settings/about_page.dart b/lib/screens/settings/about_page.dart index 3c1d4f61..6713c2f4 100644 --- a/lib/screens/settings/about_page.dart +++ b/lib/screens/settings/about_page.dart @@ -140,9 +140,7 @@ class AboutPage extends StatelessWidget { _AboutSettingsItem( icon: Icons.lyrics_outlined, title: 'Paxsenix', - subtitle: - 'Lyrics proxy for Musixmatch, Netease, Apple Music, ' - 'QQ Music, Spotify, Deezer, YouTube, Kugou, and Genius', + subtitle: context.l10n.aboutPaxsenixSubtitle, onTap: () => _launchUrl('https://lyrics.paxsenix.org'), showDivider: false, ), diff --git a/lib/screens/settings/download_settings_page.dart b/lib/screens/settings/download_settings_page.dart index ba91f0ba..01bbe84f 100644 --- a/lib/screens/settings/download_settings_page.dart +++ b/lib/screens/settings/download_settings_page.dart @@ -281,7 +281,10 @@ class _DownloadSettingsPageState extends ConsumerState { SettingsItem( icon: Icons.public, title: context.l10n.downloadSongLinkRegion, - subtitle: _getSongLinkRegionLabel(settings.songLinkRegion), + subtitle: _getSongLinkRegionLabel( + context, + settings.songLinkRegion, + ), onTap: () => _showSongLinkRegionPicker( context, ref, @@ -309,26 +312,45 @@ class _DownloadSettingsPageState extends ConsumerState { ); } - String _getSongLinkRegionLabel(String code) { - const names = { - 'US': 'United States', - 'GB': 'United Kingdom', - 'FR': 'France', - 'DE': 'Germany', - 'JP': 'Japan', - 'KR': 'South Korea', - 'IN': 'India', - 'ID': 'Indonesia', - 'BR': 'Brazil', - 'MX': 'Mexico', - 'AU': 'Australia', - 'CA': 'Canada', - 'XK': 'Kosovo', - }; + String _regionCountryName(BuildContext context, String code) { + final l10n = context.l10n; + switch (code) { + case 'US': + return l10n.regionCountryUS; + case 'GB': + return l10n.regionCountryGB; + case 'FR': + return l10n.regionCountryFR; + case 'DE': + return l10n.regionCountryDE; + case 'JP': + return l10n.regionCountryJP; + case 'KR': + return l10n.regionCountryKR; + case 'IN': + return l10n.regionCountryIN; + case 'ID': + return l10n.regionCountryID; + case 'BR': + return l10n.regionCountryBR; + case 'MX': + return l10n.regionCountryMX; + case 'AU': + return l10n.regionCountryAU; + case 'CA': + return l10n.regionCountryCA; + case 'XK': + return l10n.regionCountryXK; + default: + return code; + } + } + + String _getSongLinkRegionLabel(BuildContext context, String code) { final normalized = code.trim().toUpperCase(); final effective = normalized.isEmpty ? 'US' : normalized; - final name = names[effective]; - return name == null ? effective : '$effective - $name'; + final name = _regionCountryName(context, effective); + return name == effective ? effective : '$effective - $name'; } IconData _qualityIcon(String qualityId) { @@ -766,21 +788,6 @@ class _DownloadSettingsPageState extends ConsumerState { 'ZM', 'ZW', ]; - const names = { - 'US': 'United States', - 'GB': 'United Kingdom', - 'FR': 'France', - 'DE': 'Germany', - 'JP': 'Japan', - 'KR': 'South Korea', - 'IN': 'India', - 'ID': 'Indonesia', - 'BR': 'Brazil', - 'MX': 'Mexico', - 'AU': 'Australia', - 'CA': 'Canada', - 'XK': 'Kosovo', - }; final colorScheme = Theme.of(context).colorScheme; final normalizedCurrent = current.trim().toUpperCase(); showModalBottomSheet( @@ -821,9 +828,12 @@ class _DownloadSettingsPageState extends ConsumerState { itemBuilder: (context, index) { final code = regions[index]; final isSelected = code == normalizedCurrent; + final countryName = _regionCountryName(context, code); return ListTile( title: Text(code), - subtitle: names[code] != null ? Text(names[code]!) : null, + subtitle: countryName != code + ? Text(countryName) + : null, trailing: isSelected ? Icon(Icons.check, color: colorScheme.primary) : null, diff --git a/lib/screens/settings/files_settings_page.dart b/lib/screens/settings/files_settings_page.dart index 52165d58..3c49ee08 100644 --- a/lib/screens/settings/files_settings_page.dart +++ b/lib/screens/settings/files_settings_page.dart @@ -424,11 +424,14 @@ class _FilesSettingsPageState extends ConsumerState { required bool usePrimaryArtistOnly, required bool filterAlbumArtistContributors, }) { + final l10n = context.l10n; final statuses = [ - usePrimaryArtistOnly ? 'Primary only: On' : 'Primary only: Off', + usePrimaryArtistOnly + ? l10n.downloadPrimaryArtistOnlyOn + : l10n.downloadPrimaryArtistOnlyOff, filterAlbumArtistContributors - ? 'Album Artist metadata: Primary only' - : 'Album Artist metadata: Full', + ? l10n.downloadAlbumArtistMetadataPrimaryOnly + : l10n.downloadAlbumArtistMetadataFull, ]; return statuses.join(' | '); } diff --git a/lib/screens/track_metadata_edit_sheet.dart b/lib/screens/track_metadata_edit_sheet.dart index 01ce0606..63ea7139 100644 --- a/lib/screens/track_metadata_edit_sheet.dart +++ b/lib/screens/track_metadata_edit_sheet.dart @@ -8,6 +8,7 @@ class _ResolvedAutoFillTrack { } class _EditMetadataSheet extends StatefulWidget { + static const _onlineCoverSentinel = '__online_cover__'; final ColorScheme colorScheme; final Map initialValues; final String filePath; @@ -941,7 +942,7 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> { setState(() { _selectedCoverPath = coverOutput; _selectedCoverTempDir = tempDir.path; - _selectedCoverName = 'Online cover'; + _selectedCoverName = _EditMetadataSheet._onlineCoverSentinel; }); filledCount++; } @@ -1623,8 +1624,11 @@ class _EditMetadataSheetState extends State<_EditMetadataSheet> { child: _buildCoverPreviewTile( cs: cs, path: _selectedCoverPath!, - label: - _selectedCoverName ?? context.l10n.trackCoverSelected, + label: _selectedCoverName == + _EditMetadataSheet._onlineCoverSentinel + ? context.l10n.trackCoverOnline + : (_selectedCoverName ?? + context.l10n.trackCoverSelected), ), ), ], diff --git a/lib/widgets/update_dialog.dart b/lib/widgets/update_dialog.dart index b015a293..0c6d8c67 100644 --- a/lib/widgets/update_dialog.dart +++ b/lib/widgets/update_dialog.dart @@ -223,7 +223,10 @@ class _UpdateDialogState extends State { child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Text( - _formatChangelog(widget.updateInfo.changelog), + _formatChangelog( + widget.updateInfo.changelog, + context.l10n.updateSeeReleaseNotes, + ), style: Theme.of(context).textTheme.bodySmall?.copyWith(height: 1.5), ), ), @@ -299,7 +302,7 @@ class _UpdateDialogState extends State { } /// Format changelog - clean up markdown and extract relevant content - String _formatChangelog(String changelog) { + String _formatChangelog(String changelog, String emptyFallback) { var content = changelog; final whatsNewMatch = _whatsNewPattern.firstMatch(content); @@ -352,7 +355,7 @@ class _UpdateDialogState extends State { formatted = '${formatted.substring(0, 2000)}...'; } - return formatted.isEmpty ? 'See release notes for details.' : formatted; + return formatted.isEmpty ? emptyFallback : formatted; } }