feat(i18n): migrate settings literals
Build & Deploy Pluriwave / Análisis de código (push) Successful in 24s
Build & Deploy Pluriwave / Build APK + AAB release (push) Successful in 1m44s

This commit is contained in:
2026-05-22 13:49:12 +02:00
parent 116d878a98
commit 6480c56f99
6 changed files with 1049 additions and 51 deletions
+107 -1
View File
@@ -43,5 +43,111 @@
"timerSectionDescription": "Customize the quick presets shown when automatically stopping the radio.", "timerSectionDescription": "Customize the quick presets shown when automatically stopping the radio.",
"timerSectionRestoreRecommended": "Restore recommended times", "timerSectionRestoreRecommended": "Restore recommended times",
"newQuickAccessTitle": "New quick access", "newQuickAccessTitle": "New quick access",
"saveQuickAccessButton": "Save quick access" "saveQuickAccessButton": "Save quick access",
"settingsSafeStatus": "Safe",
"recordingsSectionTitle": "Recordings",
"recordingsFolderDialogTitle": "Select recordings folder",
"recordingsPathUpdated": "Recording path updated",
"recordingsPathSaveError": "Could not save the path: {error}",
"recordingsDefaultFolderRestored": "The internal default folder will be used",
"recordingsFolderTitle": "Recordings folder",
"recordingsPathCalculating": "Calculating path...",
"recordingsChangePath": "Change path",
"recordingsUseDefaultPath": "Use default path",
"recordingsOriginalStreamHint": "The radio is saved from the original stream, without recompressing.",
"equalizerActive": "Active",
"equalizerDisabled": "Disabled",
"equalizerEnable": "Enable equalizer",
"equalizerRealtimeSubtitle": "Changes are applied in real time to the current station.",
"equalizerPendingSubtitle": "Changes are saved and will apply when Android enables the effect.",
"equalizerPerStationTitle": "Use custom EQ for this favorite",
"equalizerPerStationActive": "Active for {stationName}",
"equalizerPerStationMain": "Using main EQ for {stationName}",
"preferredStationTitle": "Preferred station",
"preferredStationDescription": "Preselected for new alarms and available for quick playback.",
"preferredStationNoStationsTitle": "No stations available yet",
"preferredStationNoStationsSubtitle": "Save favorites or load stations to choose a preferred one.",
"preferredStationAutomaticFallback": "Automatic fallback",
"preferredStationDefaultFavorite": "Default favorite",
"preferredStationCurrent": "Current preferred: {stationName}",
"preferredStationAutoUsing": "No favorites: automatically using {stationName}",
"preferredStationPlay": "Play preferred",
"customStationsTitle": "Custom stations",
"customStationsAdd": "Add",
"customStationsEmpty": "No custom stations.",
"playAction": "Play",
"deleteAction": "Delete",
"addStationTitle": "Add station",
"stationNameLabel": "Name *",
"requiredField": "Required field",
"streamUrlLabel": "Stream URL *",
"invalidUrl": "Invalid URL",
"countryOptionalLabel": "Country (optional)",
"saveStation": "Save station",
"backupSectionTitle": "Backup",
"backupExportTitle": "Export configuration",
"backupExportSubtitle": "Favorites, custom stations, and EQ presets",
"backupImportTitle": "Import configuration",
"backupImportSubtitle": "Restore from a backup file",
"backupShareSubject": "PluriWave ? backup",
"backupShareText": "PluriWave configuration exported on {date}",
"backupExportError": "Export error: {error}",
"backupImportConfirmMessage": "This will add favorites, stations, and presets from the file. Continue?",
"backupImportSuccess": "Configuration imported successfully",
"backupImportError": "Import error: {error}",
"appVersionLoading": "Loading version...",
"appVersionSubtitle": "{version} - World radio",
"savedFavoritesTitle": "Saved favorites",
"stationFilterTitle": "Station filter",
"stationFilterSubtitle": "Only stations verified as active",
"backgroundAudioTitle": "Background audio",
"backgroundAudioSubtitle": "Continues when the screen turns off",
"dash": "?",
"@recordingsPathSaveError": {
"placeholders": {
"error": {}
}
},
"@equalizerPerStationActive": {
"placeholders": {
"stationName": {}
}
},
"@equalizerPerStationMain": {
"placeholders": {
"stationName": {}
}
},
"@preferredStationCurrent": {
"placeholders": {
"stationName": {}
}
},
"@preferredStationAutoUsing": {
"placeholders": {
"stationName": {}
}
},
"@backupShareText": {
"placeholders": {
"date": {}
}
},
"@backupExportError": {
"placeholders": {
"error": {}
}
},
"@backupImportError": {
"placeholders": {
"error": {}
}
},
"@appVersionSubtitle": {
"placeholders": {
"version": {}
}
},
"cancelAction": "Cancel",
"equalizerTitle": "Equalizer"
} }
+107 -1
View File
@@ -43,5 +43,111 @@
"timerSectionDescription": "Personalizá los accesos rápidos que aparecen al apagar la radio automáticamente.", "timerSectionDescription": "Personalizá los accesos rápidos que aparecen al apagar la radio automáticamente.",
"timerSectionRestoreRecommended": "Restaurar tiempos recomendados", "timerSectionRestoreRecommended": "Restaurar tiempos recomendados",
"newQuickAccessTitle": "Nuevo acceso rápido", "newQuickAccessTitle": "Nuevo acceso rápido",
"saveQuickAccessButton": "Guardar acceso rápido" "saveQuickAccessButton": "Guardar acceso rápido",
"settingsSafeStatus": "Seguro",
"recordingsSectionTitle": "Grabaciones",
"recordingsFolderDialogTitle": "Selecciona la carpeta de grabaciones",
"recordingsPathUpdated": "Ruta de grabaci?n actualizada",
"recordingsPathSaveError": "No se pudo guardar la ruta: {error}",
"recordingsDefaultFolderRestored": "Se usar? la carpeta interna por defecto",
"recordingsFolderTitle": "Carpeta de grabaci?n",
"recordingsPathCalculating": "Calculando ruta...",
"recordingsChangePath": "Cambiar ruta",
"recordingsUseDefaultPath": "Usar ruta por defecto",
"recordingsOriginalStreamHint": "La radio se guarda desde el stream original, sin recomprimir.",
"equalizerActive": "Activo",
"equalizerDisabled": "Desactivado",
"equalizerEnable": "Activar ecualizador",
"equalizerRealtimeSubtitle": "Los cambios se aplican en tiempo real a la emisora actual.",
"equalizerPendingSubtitle": "Se guardan los cambios y se aplicar?n cuando Android habilite el efecto.",
"equalizerPerStationTitle": "Usar EQ propio para esta favorita",
"equalizerPerStationActive": "Activo para {stationName}",
"equalizerPerStationMain": "Usando EQ principal para {stationName}",
"preferredStationTitle": "Emisora preferida",
"preferredStationDescription": "Se preselecciona al crear alarmas y puede iniciarse como reproducci?n r?pida.",
"preferredStationNoStationsTitle": "Todav?a no hay emisoras disponibles",
"preferredStationNoStationsSubtitle": "Guard? favoritas o carg? emisoras para elegir una preferida.",
"preferredStationAutomaticFallback": "Fallback autom?tico",
"preferredStationDefaultFavorite": "Favorita por defecto",
"preferredStationCurrent": "Preferida actual: {stationName}",
"preferredStationAutoUsing": "Sin favoritas: usando autom?ticamente {stationName}",
"preferredStationPlay": "Reproducir preferida",
"customStationsTitle": "Emisoras personalizadas",
"customStationsAdd": "A?adir",
"customStationsEmpty": "No hay emisoras personalizadas.",
"playAction": "Reproducir",
"deleteAction": "Eliminar",
"addStationTitle": "A?adir emisora",
"stationNameLabel": "Nombre *",
"requiredField": "Campo obligatorio",
"streamUrlLabel": "URL del stream *",
"invalidUrl": "URL no v?lida",
"countryOptionalLabel": "Pa?s (opcional)",
"saveStation": "Guardar emisora",
"backupSectionTitle": "Copia de seguridad",
"backupExportTitle": "Exportar configuraci?n",
"backupExportSubtitle": "Favoritos, emisoras custom y presets de EQ",
"backupImportTitle": "Importar configuraci?n",
"backupImportSubtitle": "Restaurar desde un fichero de copia de seguridad",
"backupShareSubject": "PluriWave ? copia de seguridad",
"backupShareText": "Configuraci?n de PluriWave exportada el {date}",
"backupExportError": "Error al exportar: {error}",
"backupImportConfirmMessage": "Esto a?adir? los favoritos, emisoras y presets del fichero. ?Continuar?",
"backupImportSuccess": "Configuraci?n importada correctamente",
"backupImportError": "Error al importar: {error}",
"appVersionLoading": "Cargando versi?n...",
"appVersionSubtitle": "{version} - Radio mundial",
"savedFavoritesTitle": "Favoritos guardados",
"stationFilterTitle": "Filtro de emisoras",
"stationFilterSubtitle": "Solo emisoras verificadas como activas",
"backgroundAudioTitle": "Audio en background",
"backgroundAudioSubtitle": "Contin?a al apagar la pantalla",
"dash": "?",
"@recordingsPathSaveError": {
"placeholders": {
"error": {}
}
},
"@equalizerPerStationActive": {
"placeholders": {
"stationName": {}
}
},
"@equalizerPerStationMain": {
"placeholders": {
"stationName": {}
}
},
"@preferredStationCurrent": {
"placeholders": {
"stationName": {}
}
},
"@preferredStationAutoUsing": {
"placeholders": {
"stationName": {}
}
},
"@backupShareText": {
"placeholders": {
"date": {}
}
},
"@backupExportError": {
"placeholders": {
"error": {}
}
},
"@backupImportError": {
"placeholders": {
"error": {}
}
},
"@appVersionSubtitle": {
"placeholders": {
"version": {}
}
},
"cancelAction": "Cancelar",
"equalizerTitle": "Ecualizador"
} }
+366
View File
@@ -301,6 +301,372 @@ abstract class AppLocalizations {
/// In es, this message translates to: /// In es, this message translates to:
/// **'Guardar acceso rápido'** /// **'Guardar acceso rápido'**
String get saveQuickAccessButton; String get saveQuickAccessButton;
/// No description provided for @settingsSafeStatus.
///
/// In es, this message translates to:
/// **'Seguro'**
String get settingsSafeStatus;
/// No description provided for @recordingsSectionTitle.
///
/// In es, this message translates to:
/// **'Grabaciones'**
String get recordingsSectionTitle;
/// No description provided for @recordingsFolderDialogTitle.
///
/// In es, this message translates to:
/// **'Selecciona la carpeta de grabaciones'**
String get recordingsFolderDialogTitle;
/// No description provided for @recordingsPathUpdated.
///
/// In es, this message translates to:
/// **'Ruta de grabaci?n actualizada'**
String get recordingsPathUpdated;
/// No description provided for @recordingsPathSaveError.
///
/// In es, this message translates to:
/// **'No se pudo guardar la ruta: {error}'**
String recordingsPathSaveError(Object error);
/// No description provided for @recordingsDefaultFolderRestored.
///
/// In es, this message translates to:
/// **'Se usar? la carpeta interna por defecto'**
String get recordingsDefaultFolderRestored;
/// No description provided for @recordingsFolderTitle.
///
/// In es, this message translates to:
/// **'Carpeta de grabaci?n'**
String get recordingsFolderTitle;
/// No description provided for @recordingsPathCalculating.
///
/// In es, this message translates to:
/// **'Calculando ruta...'**
String get recordingsPathCalculating;
/// No description provided for @recordingsChangePath.
///
/// In es, this message translates to:
/// **'Cambiar ruta'**
String get recordingsChangePath;
/// No description provided for @recordingsUseDefaultPath.
///
/// In es, this message translates to:
/// **'Usar ruta por defecto'**
String get recordingsUseDefaultPath;
/// No description provided for @recordingsOriginalStreamHint.
///
/// In es, this message translates to:
/// **'La radio se guarda desde el stream original, sin recomprimir.'**
String get recordingsOriginalStreamHint;
/// No description provided for @equalizerActive.
///
/// In es, this message translates to:
/// **'Activo'**
String get equalizerActive;
/// No description provided for @equalizerDisabled.
///
/// In es, this message translates to:
/// **'Desactivado'**
String get equalizerDisabled;
/// No description provided for @equalizerEnable.
///
/// In es, this message translates to:
/// **'Activar ecualizador'**
String get equalizerEnable;
/// No description provided for @equalizerRealtimeSubtitle.
///
/// In es, this message translates to:
/// **'Los cambios se aplican en tiempo real a la emisora actual.'**
String get equalizerRealtimeSubtitle;
/// No description provided for @equalizerPendingSubtitle.
///
/// In es, this message translates to:
/// **'Se guardan los cambios y se aplicar?n cuando Android habilite el efecto.'**
String get equalizerPendingSubtitle;
/// No description provided for @equalizerPerStationTitle.
///
/// In es, this message translates to:
/// **'Usar EQ propio para esta favorita'**
String get equalizerPerStationTitle;
/// No description provided for @equalizerPerStationActive.
///
/// In es, this message translates to:
/// **'Activo para {stationName}'**
String equalizerPerStationActive(Object stationName);
/// No description provided for @equalizerPerStationMain.
///
/// In es, this message translates to:
/// **'Usando EQ principal para {stationName}'**
String equalizerPerStationMain(Object stationName);
/// No description provided for @preferredStationTitle.
///
/// In es, this message translates to:
/// **'Emisora preferida'**
String get preferredStationTitle;
/// No description provided for @preferredStationDescription.
///
/// In es, this message translates to:
/// **'Se preselecciona al crear alarmas y puede iniciarse como reproducci?n r?pida.'**
String get preferredStationDescription;
/// No description provided for @preferredStationNoStationsTitle.
///
/// In es, this message translates to:
/// **'Todav?a no hay emisoras disponibles'**
String get preferredStationNoStationsTitle;
/// No description provided for @preferredStationNoStationsSubtitle.
///
/// In es, this message translates to:
/// **'Guard? favoritas o carg? emisoras para elegir una preferida.'**
String get preferredStationNoStationsSubtitle;
/// No description provided for @preferredStationAutomaticFallback.
///
/// In es, this message translates to:
/// **'Fallback autom?tico'**
String get preferredStationAutomaticFallback;
/// No description provided for @preferredStationDefaultFavorite.
///
/// In es, this message translates to:
/// **'Favorita por defecto'**
String get preferredStationDefaultFavorite;
/// No description provided for @preferredStationCurrent.
///
/// In es, this message translates to:
/// **'Preferida actual: {stationName}'**
String preferredStationCurrent(Object stationName);
/// No description provided for @preferredStationAutoUsing.
///
/// In es, this message translates to:
/// **'Sin favoritas: usando autom?ticamente {stationName}'**
String preferredStationAutoUsing(Object stationName);
/// No description provided for @preferredStationPlay.
///
/// In es, this message translates to:
/// **'Reproducir preferida'**
String get preferredStationPlay;
/// No description provided for @customStationsTitle.
///
/// In es, this message translates to:
/// **'Emisoras personalizadas'**
String get customStationsTitle;
/// No description provided for @customStationsAdd.
///
/// In es, this message translates to:
/// **'A?adir'**
String get customStationsAdd;
/// No description provided for @customStationsEmpty.
///
/// In es, this message translates to:
/// **'No hay emisoras personalizadas.'**
String get customStationsEmpty;
/// No description provided for @playAction.
///
/// In es, this message translates to:
/// **'Reproducir'**
String get playAction;
/// No description provided for @deleteAction.
///
/// In es, this message translates to:
/// **'Eliminar'**
String get deleteAction;
/// No description provided for @addStationTitle.
///
/// In es, this message translates to:
/// **'A?adir emisora'**
String get addStationTitle;
/// No description provided for @stationNameLabel.
///
/// In es, this message translates to:
/// **'Nombre *'**
String get stationNameLabel;
/// No description provided for @requiredField.
///
/// In es, this message translates to:
/// **'Campo obligatorio'**
String get requiredField;
/// No description provided for @streamUrlLabel.
///
/// In es, this message translates to:
/// **'URL del stream *'**
String get streamUrlLabel;
/// No description provided for @invalidUrl.
///
/// In es, this message translates to:
/// **'URL no v?lida'**
String get invalidUrl;
/// No description provided for @countryOptionalLabel.
///
/// In es, this message translates to:
/// **'Pa?s (opcional)'**
String get countryOptionalLabel;
/// No description provided for @saveStation.
///
/// In es, this message translates to:
/// **'Guardar emisora'**
String get saveStation;
/// No description provided for @backupSectionTitle.
///
/// In es, this message translates to:
/// **'Copia de seguridad'**
String get backupSectionTitle;
/// No description provided for @backupExportTitle.
///
/// In es, this message translates to:
/// **'Exportar configuraci?n'**
String get backupExportTitle;
/// No description provided for @backupExportSubtitle.
///
/// In es, this message translates to:
/// **'Favoritos, emisoras custom y presets de EQ'**
String get backupExportSubtitle;
/// No description provided for @backupImportTitle.
///
/// In es, this message translates to:
/// **'Importar configuraci?n'**
String get backupImportTitle;
/// No description provided for @backupImportSubtitle.
///
/// In es, this message translates to:
/// **'Restaurar desde un fichero de copia de seguridad'**
String get backupImportSubtitle;
/// No description provided for @backupShareSubject.
///
/// In es, this message translates to:
/// **'PluriWave ? copia de seguridad'**
String get backupShareSubject;
/// No description provided for @backupShareText.
///
/// In es, this message translates to:
/// **'Configuraci?n de PluriWave exportada el {date}'**
String backupShareText(Object date);
/// No description provided for @backupExportError.
///
/// In es, this message translates to:
/// **'Error al exportar: {error}'**
String backupExportError(Object error);
/// No description provided for @backupImportConfirmMessage.
///
/// In es, this message translates to:
/// **'Esto a?adir? los favoritos, emisoras y presets del fichero. ?Continuar?'**
String get backupImportConfirmMessage;
/// No description provided for @backupImportSuccess.
///
/// In es, this message translates to:
/// **'Configuraci?n importada correctamente'**
String get backupImportSuccess;
/// No description provided for @backupImportError.
///
/// In es, this message translates to:
/// **'Error al importar: {error}'**
String backupImportError(Object error);
/// No description provided for @appVersionLoading.
///
/// In es, this message translates to:
/// **'Cargando versi?n...'**
String get appVersionLoading;
/// No description provided for @appVersionSubtitle.
///
/// In es, this message translates to:
/// **'{version} - Radio mundial'**
String appVersionSubtitle(Object version);
/// No description provided for @savedFavoritesTitle.
///
/// In es, this message translates to:
/// **'Favoritos guardados'**
String get savedFavoritesTitle;
/// No description provided for @stationFilterTitle.
///
/// In es, this message translates to:
/// **'Filtro de emisoras'**
String get stationFilterTitle;
/// No description provided for @stationFilterSubtitle.
///
/// In es, this message translates to:
/// **'Solo emisoras verificadas como activas'**
String get stationFilterSubtitle;
/// No description provided for @backgroundAudioTitle.
///
/// In es, this message translates to:
/// **'Audio en background'**
String get backgroundAudioTitle;
/// No description provided for @backgroundAudioSubtitle.
///
/// In es, this message translates to:
/// **'Contin?a al apagar la pantalla'**
String get backgroundAudioSubtitle;
/// No description provided for @dash.
///
/// In es, this message translates to:
/// **'?'**
String get dash;
/// No description provided for @cancelAction.
///
/// In es, this message translates to:
/// **'Cancelar'**
String get cancelAction;
/// No description provided for @equalizerTitle.
///
/// In es, this message translates to:
/// **'Ecualizador'**
String get equalizerTitle;
} }
class _AppLocalizationsDelegate class _AppLocalizationsDelegate
+209
View File
@@ -117,4 +117,213 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get saveQuickAccessButton => 'Save quick access'; String get saveQuickAccessButton => 'Save quick access';
@override
String get settingsSafeStatus => 'Safe';
@override
String get recordingsSectionTitle => 'Recordings';
@override
String get recordingsFolderDialogTitle => 'Select recordings folder';
@override
String get recordingsPathUpdated => 'Recording path updated';
@override
String recordingsPathSaveError(Object error) {
return 'Could not save the path: $error';
}
@override
String get recordingsDefaultFolderRestored =>
'The internal default folder will be used';
@override
String get recordingsFolderTitle => 'Recordings folder';
@override
String get recordingsPathCalculating => 'Calculating path...';
@override
String get recordingsChangePath => 'Change path';
@override
String get recordingsUseDefaultPath => 'Use default path';
@override
String get recordingsOriginalStreamHint =>
'The radio is saved from the original stream, without recompressing.';
@override
String get equalizerActive => 'Active';
@override
String get equalizerDisabled => 'Disabled';
@override
String get equalizerEnable => 'Enable equalizer';
@override
String get equalizerRealtimeSubtitle =>
'Changes are applied in real time to the current station.';
@override
String get equalizerPendingSubtitle =>
'Changes are saved and will apply when Android enables the effect.';
@override
String get equalizerPerStationTitle => 'Use custom EQ for this favorite';
@override
String equalizerPerStationActive(Object stationName) {
return 'Active for $stationName';
}
@override
String equalizerPerStationMain(Object stationName) {
return 'Using main EQ for $stationName';
}
@override
String get preferredStationTitle => 'Preferred station';
@override
String get preferredStationDescription =>
'Preselected for new alarms and available for quick playback.';
@override
String get preferredStationNoStationsTitle => 'No stations available yet';
@override
String get preferredStationNoStationsSubtitle =>
'Save favorites or load stations to choose a preferred one.';
@override
String get preferredStationAutomaticFallback => 'Automatic fallback';
@override
String get preferredStationDefaultFavorite => 'Default favorite';
@override
String preferredStationCurrent(Object stationName) {
return 'Current preferred: $stationName';
}
@override
String preferredStationAutoUsing(Object stationName) {
return 'No favorites: automatically using $stationName';
}
@override
String get preferredStationPlay => 'Play preferred';
@override
String get customStationsTitle => 'Custom stations';
@override
String get customStationsAdd => 'Add';
@override
String get customStationsEmpty => 'No custom stations.';
@override
String get playAction => 'Play';
@override
String get deleteAction => 'Delete';
@override
String get addStationTitle => 'Add station';
@override
String get stationNameLabel => 'Name *';
@override
String get requiredField => 'Required field';
@override
String get streamUrlLabel => 'Stream URL *';
@override
String get invalidUrl => 'Invalid URL';
@override
String get countryOptionalLabel => 'Country (optional)';
@override
String get saveStation => 'Save station';
@override
String get backupSectionTitle => 'Backup';
@override
String get backupExportTitle => 'Export configuration';
@override
String get backupExportSubtitle =>
'Favorites, custom stations, and EQ presets';
@override
String get backupImportTitle => 'Import configuration';
@override
String get backupImportSubtitle => 'Restore from a backup file';
@override
String get backupShareSubject => 'PluriWave ? backup';
@override
String backupShareText(Object date) {
return 'PluriWave configuration exported on $date';
}
@override
String backupExportError(Object error) {
return 'Export error: $error';
}
@override
String get backupImportConfirmMessage =>
'This will add favorites, stations, and presets from the file. Continue?';
@override
String get backupImportSuccess => 'Configuration imported successfully';
@override
String backupImportError(Object error) {
return 'Import error: $error';
}
@override
String get appVersionLoading => 'Loading version...';
@override
String appVersionSubtitle(Object version) {
return '$version - World radio';
}
@override
String get savedFavoritesTitle => 'Saved favorites';
@override
String get stationFilterTitle => 'Station filter';
@override
String get stationFilterSubtitle => 'Only stations verified as active';
@override
String get backgroundAudioTitle => 'Background audio';
@override
String get backgroundAudioSubtitle => 'Continues when the screen turns off';
@override
String get dash => '?';
@override
String get cancelAction => 'Cancel';
@override
String get equalizerTitle => 'Equalizer';
} }
+212
View File
@@ -117,4 +117,216 @@ class AppLocalizationsEs extends AppLocalizations {
@override @override
String get saveQuickAccessButton => 'Guardar acceso rápido'; String get saveQuickAccessButton => 'Guardar acceso rápido';
@override
String get settingsSafeStatus => 'Seguro';
@override
String get recordingsSectionTitle => 'Grabaciones';
@override
String get recordingsFolderDialogTitle =>
'Selecciona la carpeta de grabaciones';
@override
String get recordingsPathUpdated => 'Ruta de grabaci?n actualizada';
@override
String recordingsPathSaveError(Object error) {
return 'No se pudo guardar la ruta: $error';
}
@override
String get recordingsDefaultFolderRestored =>
'Se usar? la carpeta interna por defecto';
@override
String get recordingsFolderTitle => 'Carpeta de grabaci?n';
@override
String get recordingsPathCalculating => 'Calculando ruta...';
@override
String get recordingsChangePath => 'Cambiar ruta';
@override
String get recordingsUseDefaultPath => 'Usar ruta por defecto';
@override
String get recordingsOriginalStreamHint =>
'La radio se guarda desde el stream original, sin recomprimir.';
@override
String get equalizerActive => 'Activo';
@override
String get equalizerDisabled => 'Desactivado';
@override
String get equalizerEnable => 'Activar ecualizador';
@override
String get equalizerRealtimeSubtitle =>
'Los cambios se aplican en tiempo real a la emisora actual.';
@override
String get equalizerPendingSubtitle =>
'Se guardan los cambios y se aplicar?n cuando Android habilite el efecto.';
@override
String get equalizerPerStationTitle => 'Usar EQ propio para esta favorita';
@override
String equalizerPerStationActive(Object stationName) {
return 'Activo para $stationName';
}
@override
String equalizerPerStationMain(Object stationName) {
return 'Usando EQ principal para $stationName';
}
@override
String get preferredStationTitle => 'Emisora preferida';
@override
String get preferredStationDescription =>
'Se preselecciona al crear alarmas y puede iniciarse como reproducci?n r?pida.';
@override
String get preferredStationNoStationsTitle =>
'Todav?a no hay emisoras disponibles';
@override
String get preferredStationNoStationsSubtitle =>
'Guard? favoritas o carg? emisoras para elegir una preferida.';
@override
String get preferredStationAutomaticFallback => 'Fallback autom?tico';
@override
String get preferredStationDefaultFavorite => 'Favorita por defecto';
@override
String preferredStationCurrent(Object stationName) {
return 'Preferida actual: $stationName';
}
@override
String preferredStationAutoUsing(Object stationName) {
return 'Sin favoritas: usando autom?ticamente $stationName';
}
@override
String get preferredStationPlay => 'Reproducir preferida';
@override
String get customStationsTitle => 'Emisoras personalizadas';
@override
String get customStationsAdd => 'A?adir';
@override
String get customStationsEmpty => 'No hay emisoras personalizadas.';
@override
String get playAction => 'Reproducir';
@override
String get deleteAction => 'Eliminar';
@override
String get addStationTitle => 'A?adir emisora';
@override
String get stationNameLabel => 'Nombre *';
@override
String get requiredField => 'Campo obligatorio';
@override
String get streamUrlLabel => 'URL del stream *';
@override
String get invalidUrl => 'URL no v?lida';
@override
String get countryOptionalLabel => 'Pa?s (opcional)';
@override
String get saveStation => 'Guardar emisora';
@override
String get backupSectionTitle => 'Copia de seguridad';
@override
String get backupExportTitle => 'Exportar configuraci?n';
@override
String get backupExportSubtitle =>
'Favoritos, emisoras custom y presets de EQ';
@override
String get backupImportTitle => 'Importar configuraci?n';
@override
String get backupImportSubtitle =>
'Restaurar desde un fichero de copia de seguridad';
@override
String get backupShareSubject => 'PluriWave ? copia de seguridad';
@override
String backupShareText(Object date) {
return 'Configuraci?n de PluriWave exportada el $date';
}
@override
String backupExportError(Object error) {
return 'Error al exportar: $error';
}
@override
String get backupImportConfirmMessage =>
'Esto a?adir? los favoritos, emisoras y presets del fichero. ?Continuar?';
@override
String get backupImportSuccess => 'Configuraci?n importada correctamente';
@override
String backupImportError(Object error) {
return 'Error al importar: $error';
}
@override
String get appVersionLoading => 'Cargando versi?n...';
@override
String appVersionSubtitle(Object version) {
return '$version - Radio mundial';
}
@override
String get savedFavoritesTitle => 'Favoritos guardados';
@override
String get stationFilterTitle => 'Filtro de emisoras';
@override
String get stationFilterSubtitle => 'Solo emisoras verificadas como activas';
@override
String get backgroundAudioTitle => 'Audio en background';
@override
String get backgroundAudioSubtitle => 'Contin?a al apagar la pantalla';
@override
String get dash => '?';
@override
String get cancelAction => 'Cancelar';
@override
String get equalizerTitle => 'Ecualizador';
} }
+48 -49
View File
@@ -33,9 +33,9 @@ class PantallaAjustes extends StatelessWidget {
title: l10n.settingsTitle, title: l10n.settingsTitle,
subtitle: l10n.settingsSubtitle, subtitle: l10n.settingsSubtitle,
glyph: PluriIconGlyph.settings, glyph: PluriIconGlyph.settings,
trailing: const PluriStatusPill( trailing: PluriStatusPill(
icon: Icons.security_rounded, icon: Icons.security_rounded,
label: 'Seguro', label: l10n.settingsSafeStatus,
), ),
), ),
const Padding( const Padding(
@@ -80,8 +80,9 @@ class _SeccionGrabaciones extends StatelessWidget {
Future<void> _seleccionarRuta(BuildContext context) async { Future<void> _seleccionarRuta(BuildContext context) async {
final estado = context.read<EstadoRadio>(); final estado = context.read<EstadoRadio>();
final messenger = ScaffoldMessenger.of(context); final messenger = ScaffoldMessenger.of(context);
final l10n = AppLocalizations.of(context);
final ruta = await FilePicker.platform.getDirectoryPath( final ruta = await FilePicker.platform.getDirectoryPath(
dialogTitle: 'Selecciona la carpeta de grabaciones', dialogTitle: l10n.recordingsFolderDialogTitle,
); );
if (ruta == null) return; if (ruta == null) return;
try { try {
@@ -91,7 +92,7 @@ class _SeccionGrabaciones extends StatelessWidget {
); );
} catch (e) { } catch (e) {
messenger.showSnackBar( messenger.showSnackBar(
SnackBar(content: Text('No se pudo guardar la ruta: $e')), SnackBar(content: Text(l10n.recordingsPathSaveError(e.toString()))),
); );
} }
} }
@@ -118,7 +119,7 @@ class _SeccionGrabaciones extends StatelessWidget {
const Icon(Icons.radio_button_checked), const Icon(Icons.radio_button_checked),
const SizedBox(width: 12), const SizedBox(width: 12),
Text( Text(
'Grabaciones', AppLocalizations.of(context).recordingsSectionTitle,
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
], ],
@@ -131,7 +132,7 @@ class _SeccionGrabaciones extends StatelessWidget {
leading: const Icon(Icons.folder_outlined), leading: const Icon(Icons.folder_outlined),
title: const Text('Carpeta de grabación'), title: const Text('Carpeta de grabación'),
subtitle: Text( subtitle: Text(
snap.data ?? 'Calculando ruta...', snap.data ?? AppLocalizations.of(context).recordingsPathCalculating,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@@ -143,13 +144,13 @@ class _SeccionGrabaciones extends StatelessWidget {
Expanded( Expanded(
child: OutlinedButton.icon( child: OutlinedButton.icon(
icon: const Icon(Icons.folder_open_rounded), icon: const Icon(Icons.folder_open_rounded),
label: const Text('Cambiar ruta'), label: Text(AppLocalizations.of(context).recordingsChangePath),
onPressed: () => _seleccionarRuta(context), onPressed: () => _seleccionarRuta(context),
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
IconButton.filledTonal( IconButton.filledTonal(
tooltip: 'Usar ruta por defecto', tooltip: AppLocalizations.of(context).recordingsUseDefaultPath,
icon: const Icon(Icons.restore_rounded), icon: const Icon(Icons.restore_rounded),
onPressed: () => _restaurarRuta(context), onPressed: () => _restaurarRuta(context),
), ),
@@ -157,7 +158,7 @@ class _SeccionGrabaciones extends StatelessWidget {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
'La radio se guarda desde el stream original, sin recomprimir.', AppLocalizations.of(context).recordingsOriginalStreamHint,
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
), ),
], ],
@@ -456,13 +457,13 @@ class _SeccionEcualizador extends StatelessWidget {
const Icon(Icons.equalizer), const Icon(Icons.equalizer),
const SizedBox(width: 12), const SizedBox(width: 12),
Text( Text(
'Ecualizador', AppLocalizations.of(ctx).equalizerTitle,
style: Theme.of(ctx).textTheme.titleMedium, style: Theme.of(ctx).textTheme.titleMedium,
), ),
const Spacer(), const Spacer(),
Chip( Chip(
label: Text( label: Text(
estado.ecualizadorActivo ? 'Activo' : 'Desactivado', estado.ecualizadorActivo ? AppLocalizations.of(ctx).equalizerActive : AppLocalizations.of(ctx).equalizerDisabled,
), ),
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
), ),
@@ -471,7 +472,7 @@ class _SeccionEcualizador extends StatelessWidget {
const SizedBox(height: 8), const SizedBox(height: 8),
SwitchListTile.adaptive( SwitchListTile.adaptive(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: const Text('Activar ecualizador'), title: Text(AppLocalizations.of(ctx).equalizerEnable),
subtitle: Text( subtitle: Text(
disponible disponible
? 'Los cambios se aplican en tiempo real a la emisora actual.' ? 'Los cambios se aplican en tiempo real a la emisora actual.'
@@ -484,11 +485,11 @@ class _SeccionEcualizador extends StatelessWidget {
const SizedBox(height: 8), const SizedBox(height: 8),
SwitchListTile.adaptive( SwitchListTile.adaptive(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: const Text('Usar EQ propio para esta favorita'), title: Text(AppLocalizations.of(ctx).equalizerPerStationTitle),
subtitle: Text( subtitle: Text(
usandoEqPropio usandoEqPropio
? 'Activo para ${emisoraActual.nombre}' ? AppLocalizations.of(ctx).equalizerPerStationActive(emisoraActual.nombre)
: 'Usando EQ principal para ${emisoraActual.nombre}', : AppLocalizations.of(ctx).equalizerPerStationMain(emisoraActual.nombre),
), ),
value: usandoEqPropio, value: usandoEqPropio,
onChanged: onChanged:
@@ -535,7 +536,7 @@ class _SeccionEmisoraPreferida extends StatelessWidget {
const Icon(Icons.radio_rounded), const Icon(Icons.radio_rounded),
const SizedBox(width: 12), const SizedBox(width: 12),
Text( Text(
'Emisora preferida', AppLocalizations.of(context).preferredStationTitle,
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
], ],
@@ -593,7 +594,7 @@ class _SeccionEmisoraPreferida extends StatelessWidget {
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: FilledButton.tonalIcon( child: FilledButton.tonalIcon(
icon: const Icon(Icons.play_arrow_rounded), icon: const Icon(Icons.play_arrow_rounded),
label: const Text('Reproducir preferida'), label: Text(AppLocalizations.of(context).preferredStationPlay),
onPressed: onPressed:
() => context.read<EstadoRadio>().reproducirEmisoraPreferida(), () => context.read<EstadoRadio>().reproducirEmisoraPreferida(),
), ),
@@ -634,7 +635,7 @@ class _SeccionEmisoras extends StatelessWidget {
const Icon(Icons.add_circle_outline), const Icon(Icons.add_circle_outline),
const SizedBox(width: 12), const SizedBox(width: 12),
Text( Text(
'Emisoras personalizadas', AppLocalizations.of(context).customStationsTitle,
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
const Spacer(), const Spacer(),
@@ -646,11 +647,11 @@ class _SeccionEmisoras extends StatelessWidget {
], ],
), ),
if (custom.isEmpty) if (custom.isEmpty)
const Padding( Padding(
padding: EdgeInsets.only(top: 8), padding: const EdgeInsets.only(top: 8),
child: Text( child: Text(
'No hay emisoras personalizadas.', AppLocalizations.of(context).customStationsEmpty,
style: TextStyle(color: Colors.grey), style: const TextStyle(color: Colors.grey),
), ),
) )
else else
@@ -669,13 +670,13 @@ class _SeccionEmisoras extends StatelessWidget {
children: [ children: [
IconButton( IconButton(
icon: const Icon(Icons.play_arrow), icon: const Icon(Icons.play_arrow),
tooltip: 'Reproducir', tooltip: AppLocalizations.of(context).playAction,
onPressed: onPressed:
() => context.read<EstadoRadio>().reproducir(emisora), () => context.read<EstadoRadio>().reproducir(emisora),
), ),
IconButton( IconButton(
icon: const Icon(Icons.delete_outline), icon: const Icon(Icons.delete_outline),
tooltip: 'Eliminar', tooltip: AppLocalizations.of(context).deleteAction,
onPressed: onPressed:
() => context () => context
.read<EstadoRadio>() .read<EstadoRadio>()
@@ -753,27 +754,27 @@ class _FormularioEmisoraState extends State<_FormularioEmisora> {
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
controller: _nombreCtrl, controller: _nombreCtrl,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'Nombre *', labelText: AppLocalizations.of(context).stationNameLabel,
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
validator: validator:
(v) => (v) =>
v == null || v.trim().isEmpty v == null || v.trim().isEmpty
? 'Campo obligatorio' ? AppLocalizations.of(context).requiredField
: null, : null,
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
TextFormField( TextFormField(
controller: _urlCtrl, controller: _urlCtrl,
decoration: const InputDecoration( decoration: InputDecoration(
labelText: 'URL del stream *', labelText: AppLocalizations.of(context).streamUrlLabel,
hintText: 'http://stream.ejemplo.com:8000/radio', hintText: 'http://stream.ejemplo.com:8000/radio',
border: OutlineInputBorder(), border: const OutlineInputBorder(),
), ),
keyboardType: TextInputType.url, keyboardType: TextInputType.url,
validator: (v) { validator: (v) {
if (v == null || v.trim().isEmpty) return 'Campo obligatorio'; if (v == null || v.trim().isEmpty) return AppLocalizations.of(context).requiredField;
final uri = Uri.tryParse(v.trim()); final uri = Uri.tryParse(v.trim());
if (uri == null || !uri.hasScheme) return 'URL no válida'; if (uri == null || !uri.hasScheme) return 'URL no válida';
return null; return null;
@@ -797,7 +798,7 @@ class _FormularioEmisoraState extends State<_FormularioEmisora> {
width: 20, width: 20,
child: CircularProgressIndicator(strokeWidth: 2), child: CircularProgressIndicator(strokeWidth: 2),
) )
: const Text('Guardar emisora'), : Text(AppLocalizations.of(context).saveStation),
), ),
], ],
), ),
@@ -829,7 +830,7 @@ class _SeccionBackup extends StatelessWidget {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of( ScaffoldMessenger.of(
context, context,
).showSnackBar(SnackBar(content: Text('Error al exportar: $e'))); ).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).backupExportError(e.toString()))));
} }
} }
} }
@@ -858,11 +859,11 @@ class _SeccionBackup extends StatelessWidget {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.pop(ctx, false), onPressed: () => Navigator.pop(ctx, false),
child: const Text('Cancelar'), child: Text(AppLocalizations.of(ctx).cancelAction),
), ),
FilledButton( FilledButton(
onPressed: () => Navigator.pop(ctx, true), onPressed: () => Navigator.pop(ctx, true),
child: const Text('Importar'), child: Text(AppLocalizations.of(ctx).backupImportTitle),
), ),
], ],
), ),
@@ -883,7 +884,7 @@ class _SeccionBackup extends StatelessWidget {
if (context.mounted) { if (context.mounted) {
ScaffoldMessenger.of( ScaffoldMessenger.of(
context, context,
).showSnackBar(SnackBar(content: Text('Error al importar: $e'))); ).showSnackBar(SnackBar(content: Text(AppLocalizations.of(context).backupImportError(e.toString()))));
} }
} }
} }
@@ -899,7 +900,7 @@ class _SeccionBackup extends StatelessWidget {
const Icon(Icons.backup_outlined), const Icon(Icons.backup_outlined),
const SizedBox(width: 12), const SizedBox(width: 12),
Text( Text(
'Copia de seguridad', AppLocalizations.of(context).backupSectionTitle,
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
], ],
@@ -908,16 +909,14 @@ class _SeccionBackup extends StatelessWidget {
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
leading: const Icon(Icons.upload_outlined), leading: const Icon(Icons.upload_outlined),
title: const Text('Exportar configuración'), title: const Text('Exportar configuración'),
subtitle: const Text('Favoritos, emisoras custom y presets de EQ'), subtitle: Text(AppLocalizations.of(context).backupExportSubtitle),
onTap: () => _exportar(context), onTap: () => _exportar(context),
), ),
ListTile( ListTile(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
leading: const Icon(Icons.download_outlined), leading: const Icon(Icons.download_outlined),
title: const Text('Importar configuración'), title: const Text('Importar configuración'),
subtitle: const Text( subtitle: Text(AppLocalizations.of(context).backupImportSubtitle),
'Restaurar desde un fichero de copia de seguridad',
),
onTap: () => _importar(context), onTap: () => _importar(context),
), ),
], ],
@@ -950,7 +949,7 @@ class _SeccionInfo extends StatelessWidget {
variant: PluriIconVariant.filled, variant: PluriIconVariant.filled,
), ),
title: const Text('PluriWave'), title: const Text('PluriWave'),
subtitle: Text('$version - Radio mundial'), subtitle: Text(AppLocalizations.of(ctx).appVersionSubtitle(version)),
); );
}, },
), ),
@@ -960,19 +959,19 @@ class _SeccionInfo extends StatelessWidget {
(ctx, snap) => ListTile( (ctx, snap) => ListTile(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
leading: const Icon(Icons.favorite_outline), leading: const Icon(Icons.favorite_outline),
title: const Text('Favoritos guardados'), title: Text(AppLocalizations.of(ctx).savedFavoritesTitle),
trailing: Text( trailing: Text(
snap.data?.toString() ?? '', snap.data?.toString() ?? '',
style: Theme.of(ctx).textTheme.bodyLarge, style: Theme.of(ctx).textTheme.bodyLarge,
), ),
), ),
), ),
const ListTile( ListTile(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
leading: Icon(Icons.verified_outlined), leading: const Icon(Icons.verified_outlined),
title: Text('Filtro de emisoras'), title: Text(AppLocalizations.of(ctx).stationFilterTitle),
subtitle: Text('Solo emisoras verificadas como activas'), subtitle: Text(AppLocalizations.of(ctx).stationFilterSubtitle),
trailing: Icon(Icons.check_circle, color: Colors.green), trailing: const Icon(Icons.check_circle, color: Colors.green),
), ),
const ListTile( const ListTile(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,