diff --git a/Audiomatic/App.xaml.cs b/Audiomatic/App.xaml.cs
index 4c36155..4aa4f2b 100644
--- a/Audiomatic/App.xaml.cs
+++ b/Audiomatic/App.xaml.cs
@@ -15,6 +15,7 @@ public App()
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
SetCurrentProcessExplicitAppUserModelID("Audiomatic.App");
+ Strings.Language = SettingsManager.LoadLanguage();
_window = new MainWindow();
_window.Activate();
}
diff --git a/Audiomatic/LibraryWindow.xaml b/Audiomatic/LibraryWindow.xaml
index f059b54..8bbd89f 100644
--- a/Audiomatic/LibraryWindow.xaml
+++ b/Audiomatic/LibraryWindow.xaml
@@ -18,7 +18,7 @@
-
rows)
ApplySort();
}
+ private void ApplyLocalization()
+ {
+ LibraryTitleText.Text = Strings.T("Library");
+ EmptyStateText.Text = Strings.T("No tracks in library.");
+ }
+
private void ApplyTheme(string theme)
{
if (Content is not FrameworkElement root) return;
@@ -96,8 +103,8 @@ private void ApplySort()
private void UpdateHeaderTexts()
{
- TitleHeaderText.Text = BuildHeader("Titre", _sortColumn == LibrarySortColumn.Title);
- FolderHeaderText.Text = BuildHeader("Dossier", _sortColumn == LibrarySortColumn.Folder);
+ TitleHeaderText.Text = BuildHeader(Strings.T("Title"), _sortColumn == LibrarySortColumn.Title);
+ FolderHeaderText.Text = BuildHeader(Strings.T("Folder"), _sortColumn == LibrarySortColumn.Folder);
}
private string BuildHeader(string label, bool isActive)
diff --git a/Audiomatic/MainWindow.xaml b/Audiomatic/MainWindow.xaml
index 9ff7008..5bd4085 100644
--- a/Audiomatic/MainWindow.xaml
+++ b/Audiomatic/MainWindow.xaml
@@ -269,7 +269,7 @@
-
@@ -281,7 +281,7 @@
-
@@ -293,7 +293,7 @@
-
@@ -389,7 +389,7 @@
-
@@ -415,7 +415,7 @@
IsItemClickEnabled="True"
ItemClick="RadioHistory_ItemClick">
-
@@ -517,7 +517,7 @@
Padding="6,3" Click="ChooseFolder_Click">
-
@@ -531,7 +531,7 @@
FontSize="11"
Margin="0,0,6,0"/>
-
@@ -63,7 +63,7 @@
-
-
@@ -96,9 +96,9 @@
-
-
@@ -111,9 +111,9 @@
-
-
diff --git a/Audiomatic/SettingsWindow.xaml.cs b/Audiomatic/SettingsWindow.xaml.cs
index fd3c7e4..2b4f5e9 100644
--- a/Audiomatic/SettingsWindow.xaml.cs
+++ b/Audiomatic/SettingsWindow.xaml.cs
@@ -43,12 +43,45 @@ public SettingsWindow(SystemBackdrop? backdrop,
if (backdrop != null)
this.SystemBackdrop = backdrop;
+ ApplyLocalization();
LoadSettings();
LoadFolders();
ApplyTheme(SettingsManager.LoadTheme());
_suppressEvents = false;
}
+ private void ApplyLocalization()
+ {
+ TitleBarText.Text = Strings.T("Settings");
+ SelectorFolders.Text = Strings.T("Folders");
+ SelectorAppearance.Text = Strings.T("Appearance");
+
+ // Folders page
+ FoldersHeaderText.Text = Strings.T("Music Folders");
+ FoldersDescText.Text = Strings.T("Add folders containing your music files. They will be scanned for audio tracks.");
+ AddFolderText.Text = Strings.T("Add Folder");
+ ScanNowText.Text = Strings.T("Scan Now");
+
+ // Appearance page
+ ThemeHeaderText.Text = Strings.T("Theme");
+ ThemeDescText.Text = Strings.T("Choose the color theme for the application.");
+ RadioThemeSystem.Content = Strings.T("System");
+ RadioThemeLight.Content = Strings.T("Light");
+ RadioThemeDark.Content = Strings.T("Dark");
+
+ BackdropHeaderText.Text = Strings.T("Backdrop Effect");
+ BackdropDescText.Text = Strings.T("Choose the visual effect applied to the window background.");
+ RadioAcrylic.Content = Strings.T("Acrylic");
+ RadioMica.Content = Strings.T("Mica");
+ RadioMicaAlt.Content = Strings.T("Mica Alt");
+ RadioNone.Content = Strings.T("None");
+
+ VizHeaderText.Text = Strings.T("Visualizer");
+ VizDescText.Text = Strings.T("Frame rate for the audio visualizer.");
+ RadioFps30.Content = Strings.T("30 FPS");
+ RadioFps60.Content = Strings.T("60 FPS");
+ }
+
private void LoadSettings()
{
var backdrop = SettingsManager.LoadBackdrop();
@@ -112,7 +145,7 @@ private void LoadFolders()
{
FoldersList.Children.Add(new TextBlock
{
- Text = "No folders added yet.",
+ Text = Strings.T("No folders added yet."),
Style = (Style)Application.Current.Resources["CaptionTextBlockStyle"],
Foreground = ThemeHelper.Brush("TextFillColorTertiaryBrush")
});
@@ -137,7 +170,7 @@ private async void AddFolder_Click(object sender, RoutedEventArgs e)
LoadFolders();
// Auto-scan the new folder
- ScanStatus.Text = "Scanning...";
+ ScanStatus.Text = Strings.T("Scanning...");
ScanProgress.Visibility = Visibility.Visible;
ScanProgress.IsIndeterminate = true;
@@ -151,22 +184,22 @@ private async void AddFolder_Click(object sender, RoutedEventArgs e)
ScanProgress.IsIndeterminate = false;
ScanProgress.Value = (double)p.scanned / p.total * 100;
}
- ScanStatus.Text = $"Scanned {p.scanned}/{p.total} files...";
+ ScanStatus.Text = Strings.T("Scanned {0}/{1} files...", p.scanned, p.total);
});
try
{
var added = await LibraryManager.ScanFolderAsync(folderId, folder.Path, progress, _scanCts.Token);
- ScanStatus.Text = $"Done. {added} tracks added.";
+ ScanStatus.Text = Strings.T("Done. {0} tracks added.", added);
_onLibraryChanged?.Invoke();
}
catch (OperationCanceledException)
{
- ScanStatus.Text = "Scan cancelled.";
+ ScanStatus.Text = Strings.T("Scan cancelled.");
}
catch (Exception ex)
{
- ScanStatus.Text = $"Error: {ex.Message}";
+ ScanStatus.Text = Strings.T("Error: {0}", ex.Message);
}
finally
{
@@ -186,7 +219,7 @@ private void RemoveFolder_Click(object sender, RoutedEventArgs e)
private async void Scan_Click(object sender, RoutedEventArgs e)
{
- ScanStatus.Text = "Scanning all folders...";
+ ScanStatus.Text = Strings.T("Scanning all folders...");
ScanProgress.Visibility = Visibility.Visible;
ScanProgress.IsIndeterminate = true;
ScanButton.IsEnabled = false;
@@ -201,22 +234,22 @@ private async void Scan_Click(object sender, RoutedEventArgs e)
ScanProgress.IsIndeterminate = false;
ScanProgress.Value = (double)p.scanned / p.total * 100;
}
- ScanStatus.Text = $"Scanned {p.scanned}/{p.total} files...";
+ ScanStatus.Text = Strings.T("Scanned {0}/{1} files...", p.scanned, p.total);
});
try
{
var added = await LibraryManager.ScanAllFoldersAsync(progress, _scanCts.Token);
- ScanStatus.Text = $"Done. {added} new tracks found.";
+ ScanStatus.Text = Strings.T("Done. {0} new tracks found.", added);
_onLibraryChanged?.Invoke();
}
catch (OperationCanceledException)
{
- ScanStatus.Text = "Scan cancelled.";
+ ScanStatus.Text = Strings.T("Scan cancelled.");
}
catch (Exception ex)
{
- ScanStatus.Text = $"Error: {ex.Message}";
+ ScanStatus.Text = Strings.T("Error: {0}", ex.Message);
}
finally
{
diff --git a/Audiomatic/Strings.cs b/Audiomatic/Strings.cs
new file mode 100644
index 0000000..23f61c4
--- /dev/null
+++ b/Audiomatic/Strings.cs
@@ -0,0 +1,246 @@
+namespace Audiomatic;
+
+///
+/// Simple i18n system — call Strings.T("key") to get the current-language translation.
+///
+public static class Strings
+{
+ private static string _lang = "en";
+
+ public static string Language
+ {
+ get => _lang;
+ set => _lang = value ?? "en";
+ }
+
+ /// Translate a key to the current language. Returns the key itself if not found.
+ public static string T(string key)
+ {
+ if (Translations.TryGetValue(key, out var map) && map.TryGetValue(_lang, out var val))
+ return val;
+ // Fallback to English
+ if (Translations.TryGetValue(key, out map) && map.TryGetValue("en", out val))
+ return val;
+ return key;
+ }
+
+ /// Translate with format arguments: Strings.T("key", arg1, arg2)
+ public static string T(string key, params object[] args)
+ {
+ var template = T(key);
+ try { return string.Format(template, args); }
+ catch { return template; }
+ }
+
+ // ── All translations ────────────────────────────────────────
+ // Key → { "en" → English, "fr" → French }
+
+ private static readonly Dictionary> Translations = new()
+ {
+ // ── Navigation ──────────────────────────────────────────
+ ["Library"] = new() { ["en"] = "Library", ["fr"] = "Bibliothèque" },
+ ["Playlists"] = new() { ["en"] = "Playlists", ["fr"] = "Playlists" },
+ ["Queue"] = new() { ["en"] = "Queue", ["fr"] = "File d'attente" },
+ ["Radio"] = new() { ["en"] = "Radio", ["fr"] = "Radio" },
+ ["Podcasts"] = new() { ["en"] = "Podcasts", ["fr"] = "Podcasts" },
+ ["Albums"] = new() { ["en"] = "Albums", ["fr"] = "Albums" },
+ ["Artists"] = new() { ["en"] = "Artists", ["fr"] = "Artistes" },
+ ["Visualizer"] = new() { ["en"] = "Visualizer", ["fr"] = "Visualiseur" },
+ ["Equalizer"] = new() { ["en"] = "Equalizer", ["fr"] = "Égaliseur" },
+ ["Media"] = new() { ["en"] = "Media", ["fr"] = "Média" },
+
+ // ── Player ──────────────────────────────────────────────
+ ["No track"] = new() { ["en"] = "No track", ["fr"] = "Aucune piste" },
+ ["LIVE"] = new() { ["en"] = "LIVE", ["fr"] = "EN DIRECT" },
+ ["No track playing"] = new() { ["en"] = "No track playing", ["fr"] = "Aucune piste en lecture" },
+
+ // ── Tooltips ────────────────────────────────────────────
+ ["Compact (Ctrl+L)"] = new() { ["en"] = "Compact (Ctrl+L)", ["fr"] = "Compact (Ctrl+L)" },
+ ["Pin on top"] = new() { ["en"] = "Pin on top", ["fr"] = "Épingler au premier plan" },
+ ["Shuffle"] = new() { ["en"] = "Shuffle", ["fr"] = "Aléatoire" },
+ ["Previous"] = new() { ["en"] = "Previous", ["fr"] = "Précédent" },
+ ["Next"] = new() { ["en"] = "Next", ["fr"] = "Suivant" },
+ ["Repeat"] = new() { ["en"] = "Repeat", ["fr"] = "Répéter" },
+ ["Playback Speed"] = new() { ["en"] = "Playback Speed", ["fr"] = "Vitesse de lecture" },
+ ["Back to playlists"] = new() { ["en"] = "Back to playlists", ["fr"] = "Retour aux playlists" },
+ ["Back to albums"] = new() { ["en"] = "Back to albums", ["fr"] = "Retour aux albums" },
+ ["Back to artists"] = new() { ["en"] = "Back to artists", ["fr"] = "Retour aux artistes" },
+ ["New Playlist"] = new() { ["en"] = "New Playlist", ["fr"] = "Nouvelle playlist" },
+ ["Clear Queue"] = new() { ["en"] = "Clear Queue", ["fr"] = "Vider la file" },
+ ["Play stream"] = new() { ["en"] = "Play stream", ["fr"] = "Lire le flux" },
+ ["Back"] = new() { ["en"] = "Back", ["fr"] = "Retour" },
+ ["Settings"] = new() { ["en"] = "Settings", ["fr"] = "Paramètres" },
+
+ // ── Search & Sort ───────────────────────────────────────
+ ["Search"] = new() { ["en"] = "Search", ["fr"] = "Rechercher" },
+ ["Title"] = new() { ["en"] = "Title", ["fr"] = "Titre" },
+ ["Artist"] = new() { ["en"] = "Artist", ["fr"] = "Artiste" },
+ ["Album"] = new() { ["en"] = "Album", ["fr"] = "Album" },
+ ["Duration"] = new() { ["en"] = "Duration", ["fr"] = "Durée" },
+ ["BPM"] = new() { ["en"] = "BPM", ["fr"] = "BPM" },
+ ["Ascending"] = new() { ["en"] = "Ascending", ["fr"] = "Croissant" },
+ ["Folder"] = new() { ["en"] = "Folder", ["fr"] = "Dossier" },
+
+ // ── Radio ───────────────────────────────────────────────
+ ["Radio Stream"] = new() { ["en"] = "Radio Stream", ["fr"] = "Flux radio" },
+ ["Enter stream URL (e.g. http://...)"] = new() { ["en"] = "Enter stream URL (e.g. http://...)", ["fr"] = "Entrer l'URL du flux (ex: http://...)" },
+ ["Recent stations"] = new() { ["en"] = "Recent stations", ["fr"] = "Stations récentes" },
+ ["Search podcasts..."] = new() { ["en"] = "Search podcasts...", ["fr"] = "Rechercher des podcasts..." },
+ ["Invalid URL. Please enter a valid http/https stream URL."] = new() { ["en"] = "Invalid URL. Please enter a valid http/https stream URL.", ["fr"] = "URL invalide. Veuillez entrer une URL de flux http/https valide." },
+ ["Connecting..."] = new() { ["en"] = "Connecting...", ["fr"] = "Connexion..." },
+ ["Playing: {0}"] = new() { ["en"] = "Playing: {0}", ["fr"] = "Lecture : {0}" },
+
+ // ── Speed ───────────────────────────────────────────────
+ ["Speed"] = new() { ["en"] = "Speed", ["fr"] = "Vitesse" },
+ ["Normal"] = new() { ["en"] = "Normal", ["fr"] = "Normal" },
+
+ // ── Context menu items ──────────────────────────────────
+ ["Play"] = new() { ["en"] = "Play", ["fr"] = "Lire" },
+ ["Play Next"] = new() { ["en"] = "Play Next", ["fr"] = "Lire ensuite" },
+ ["Add to Queue"] = new() { ["en"] = "Add to Queue", ["fr"] = "Ajouter à la file" },
+ ["Add to Playlist"] = new() { ["en"] = "Add to Playlist", ["fr"] = "Ajouter à la playlist" },
+ ["New Playlist..."] = new() { ["en"] = "New Playlist...", ["fr"] = "Nouvelle playlist..." },
+ ["Detect BPM"] = new() { ["en"] = "Detect BPM", ["fr"] = "Détecter le BPM" },
+ ["{0} BPM"] = new() { ["en"] = "{0} BPM", ["fr"] = "{0} BPM" },
+ ["Edit Tags"] = new() { ["en"] = "Edit Tags", ["fr"] = "Modifier les tags" },
+ ["Remove from Playlist"] = new() { ["en"] = "Remove from Playlist", ["fr"] = "Retirer de la playlist" },
+ ["Rename"] = new() { ["en"] = "Rename", ["fr"] = "Renommer" },
+ ["Delete"] = new() { ["en"] = "Delete", ["fr"] = "Supprimer" },
+ ["Move Up"] = new() { ["en"] = "Move Up", ["fr"] = "Monter" },
+ ["Move Down"] = new() { ["en"] = "Move Down", ["fr"] = "Descendre" },
+ ["Remove"] = new() { ["en"] = "Remove", ["fr"] = "Retirer" },
+ ["Expand"] = new() { ["en"] = "Expand", ["fr"] = "Agrandir" },
+
+ // ── Radio station context ───────────────────────────────
+ ["Rename Station"] = new() { ["en"] = "Rename Station", ["fr"] = "Renommer la station" },
+ ["Confirm"] = new() { ["en"] = "Confirm", ["fr"] = "Confirmer" },
+
+ // ── Podcast ─────────────────────────────────────────────
+ ["Episodes"] = new() { ["en"] = "Episodes", ["fr"] = "Épisodes" },
+ ["Subscribe"] = new() { ["en"] = "Subscribe", ["fr"] = "S'abonner" },
+ ["Subscribed"] = new() { ["en"] = "Subscribed", ["fr"] = "Abonné" },
+ ["Unsubscribe"] = new() { ["en"] = "Unsubscribe", ["fr"] = "Se désabonner" },
+ ["Download"] = new() { ["en"] = "Download", ["fr"] = "Télécharger" },
+ ["Cancel Download"] = new() { ["en"] = "Cancel Download", ["fr"] = "Annuler le téléchargement" },
+ ["Delete Download"] = new() { ["en"] = "Delete Download", ["fr"] = "Supprimer le téléchargement" },
+ ["Mark as read"] = new() { ["en"] = "Mark as read", ["fr"] = "Marquer comme lu" },
+ ["Mark as unread"] = new() { ["en"] = "Mark as unread", ["fr"] = "Marquer comme non lu" },
+ ["Downloading..."] = new() { ["en"] = "Downloading...", ["fr"] = "Téléchargement..." },
+ ["Played"] = new() { ["en"] = "Played", ["fr"] = "Lu" },
+ ["Loading episodes..."] = new() { ["en"] = "Loading episodes...", ["fr"] = "Chargement des épisodes..." },
+ ["No episodes found."] = new() { ["en"] = "No episodes found.", ["fr"] = "Aucun épisode trouvé." },
+ ["Error loading episodes: {0}"] = new() { ["en"] = "Error loading episodes: {0}", ["fr"] = "Erreur de chargement des épisodes : {0}" },
+ ["Searching..."] = new() { ["en"] = "Searching...", ["fr"] = "Recherche..." },
+ ["No podcasts found."] = new() { ["en"] = "No podcasts found.", ["fr"] = "Aucun podcast trouvé." },
+ ["Download failed: {0}"] = new() { ["en"] = "Download failed: {0}", ["fr"] = "Échec du téléchargement : {0}" },
+
+ // ── Dialogs ─────────────────────────────────────────────
+ ["Create"] = new() { ["en"] = "Create", ["fr"] = "Créer" },
+ ["Cancel"] = new() { ["en"] = "Cancel", ["fr"] = "Annuler" },
+ ["Playlist name"] = new() { ["en"] = "Playlist name", ["fr"] = "Nom de la playlist" },
+ ["Rename Playlist"] = new() { ["en"] = "Rename Playlist", ["fr"] = "Renommer la playlist" },
+
+ // ── Metadata editor ─────────────────────────────────────
+ ["Change"] = new() { ["en"] = "Change", ["fr"] = "Changer" },
+ ["Save"] = new() { ["en"] = "Save", ["fr"] = "Enregistrer" },
+ ["Choose color"] = new() { ["en"] = "Choose color", ["fr"] = "Choisir la couleur" },
+
+ // ── Settings flyout ─────────────────────────────────────
+ ["Actions"] = new() { ["en"] = "Actions", ["fr"] = "Actions" },
+ ["Add Folder"] = new() { ["en"] = "Add Folder", ["fr"] = "Ajouter un dossier" },
+ ["Scan Library"] = new() { ["en"] = "Scan Library", ["fr"] = "Scanner la bibliothèque" },
+ ["Reset Library"] = new() { ["en"] = "Reset Library", ["fr"] = "Réinitialiser la bibliothèque" },
+ ["Backdrop"] = new() { ["en"] = "Backdrop", ["fr"] = "Arrière-plan" },
+ ["Acrylic"] = new() { ["en"] = "Acrylic", ["fr"] = "Acrylique" },
+ ["Custom Acrylic"] = new() { ["en"] = "Custom Acrylic", ["fr"] = "Acrylique personnalisé" },
+ ["Mica"] = new() { ["en"] = "Mica", ["fr"] = "Mica" },
+ ["Mica Alt"] = new() { ["en"] = "Mica Alt", ["fr"] = "Mica Alt" },
+ ["None"] = new() { ["en"] = "None", ["fr"] = "Aucun" },
+ ["Theme"] = new() { ["en"] = "Theme", ["fr"] = "Thème" },
+ ["System"] = new() { ["en"] = "System", ["fr"] = "Système" },
+ ["Light"] = new() { ["en"] = "Light", ["fr"] = "Clair" },
+ ["Dark"] = new() { ["en"] = "Dark", ["fr"] = "Sombre" },
+ ["Accent Color"] = new() { ["en"] = "Accent Color", ["fr"] = "Couleur d'accentuation" },
+ ["Choose Accent..."] = new() { ["en"] = "Choose Accent...", ["fr"] = "Choisir l'accent..." },
+ ["30 FPS"] = new() { ["en"] = "30 FPS", ["fr"] = "30 IPS" },
+ ["60 FPS"] = new() { ["en"] = "60 FPS", ["fr"] = "60 IPS" },
+ ["Compact Mode"] = new() { ["en"] = "Compact Mode", ["fr"] = "Mode compact" },
+ ["Mini Player"] = new() { ["en"] = "Mini Player", ["fr"] = "Mini lecteur" },
+ ["Unpin from Top"] = new() { ["en"] = "Unpin from Top", ["fr"] = "Détacher du premier plan" },
+ ["Pin on Top"] = new() { ["en"] = "Pin on Top", ["fr"] = "Épingler au premier plan" },
+ ["Sleep Timer"] = new() { ["en"] = "Sleep Timer", ["fr"] = "Minuterie de veille" },
+ ["Sleep ({0} min)"] = new() { ["en"] = "Sleep ({0} min)", ["fr"] = "Veille ({0} min)" },
+ ["Quit"] = new() { ["en"] = "Quit", ["fr"] = "Quitter" },
+
+ // ── Language setting ────────────────────────────────────
+ ["Language"] = new() { ["en"] = "Language", ["fr"] = "Langue" },
+ ["English"] = new() { ["en"] = "English", ["fr"] = "Anglais" },
+ ["French"] = new() { ["en"] = "French", ["fr"] = "Français" },
+
+ // ── Custom Acrylic settings ─────────────────────────────
+ ["Tint Opacity"] = new() { ["en"] = "Tint Opacity", ["fr"] = "Opacité de teinte" },
+ ["Luminosity"] = new() { ["en"] = "Luminosity", ["fr"] = "Luminosité" },
+ ["Tint"] = new() { ["en"] = "Tint", ["fr"] = "Teinte" },
+ ["Fallback"] = new() { ["en"] = "Fallback", ["fr"] = "Repli" },
+ ["Style"] = new() { ["en"] = "Style", ["fr"] = "Style" },
+
+ // ── Equalizer ───────────────────────────────────────────
+ ["Preamp"] = new() { ["en"] = "Preamp", ["fr"] = "Préampli" },
+ ["Reset"] = new() { ["en"] = "Reset", ["fr"] = "Réinitialiser" },
+
+ // ── Status messages ─────────────────────────────────────
+ ["Scanning..."] = new() { ["en"] = "Scanning...", ["fr"] = "Analyse..." },
+ ["{0} tracks"] = new() { ["en"] = "{0} tracks", ["fr"] = "{0} pistes" },
+ ["{0} albums"] = new() { ["en"] = "{0} albums", ["fr"] = "{0} albums" },
+ ["{0} artists"] = new() { ["en"] = "{0} artists", ["fr"] = "{0} artistes" },
+ ["{0} in queue"] = new() { ["en"] = "{0} in queue", ["fr"] = "{0} dans la file" },
+ ["{0} playlists"] = new() { ["en"] = "{0} playlists", ["fr"] = "{0} playlists" },
+ ["{0} playlist"] = new() { ["en"] = "{0} playlist", ["fr"] = "{0} playlist" },
+ ["{0} sessions"] = new() { ["en"] = "{0} sessions", ["fr"] = "{0} sessions" },
+ ["{0} session"] = new() { ["en"] = "{0} session", ["fr"] = "{0} session" },
+ ["Error: {0}"] = new() { ["en"] = "Error: {0}", ["fr"] = "Erreur : {0}" },
+ ["0 tracks"] = new() { ["en"] = "0 tracks", ["fr"] = "0 pistes" },
+
+ // ── Bottom bar ──────────────────────────────────────────
+ ["Choose Folder"] = new() { ["en"] = "Choose Folder", ["fr"] = "Choisir un dossier" },
+
+ // ── Drag & drop ─────────────────────────────────────────
+ ["Add to Library"] = new() { ["en"] = "Add to Library", ["fr"] = "Ajouter à la bibliothèque" },
+
+ // ── Media control ───────────────────────────────────────
+ ["No media playing"] = new() { ["en"] = "No media playing", ["fr"] = "Aucun média en lecture" },
+ ["Play music or a video to control it here"] = new() { ["en"] = "Play music or a video to control it here", ["fr"] = "Lancez de la musique ou une vidéo pour la contrôler ici" },
+
+ // ── Sleep timer details ─────────────────────────────────
+ ["{0} min remaining"] = new() { ["en"] = "{0} min remaining", ["fr"] = "{0} min restantes" },
+ ["{0}s remaining"] = new() { ["en"] = "{0}s remaining", ["fr"] = "{0}s restantes" },
+ ["Cancel Timer"] = new() { ["en"] = "Cancel Timer", ["fr"] = "Annuler la minuterie" },
+ ["{0} min"] = new() { ["en"] = "{0} min", ["fr"] = "{0} min" },
+ ["{0}h {1}min"] = new() { ["en"] = "{0}h {1}min", ["fr"] = "{0}h {1}min" },
+ ["{0}h"] = new() { ["en"] = "{0}h", ["fr"] = "{0}h" },
+
+ // ── Settings window ─────────────────────────────────────
+ ["Folders"] = new() { ["en"] = "Folders", ["fr"] = "Dossiers" },
+ ["Appearance"] = new() { ["en"] = "Appearance", ["fr"] = "Apparence" },
+ ["Music Folders"] = new() { ["en"] = "Music Folders", ["fr"] = "Dossiers musicaux" },
+ ["Add folders containing your music files. They will be scanned for audio tracks."] = new() { ["en"] = "Add folders containing your music files. They will be scanned for audio tracks.", ["fr"] = "Ajoutez des dossiers contenant vos fichiers musicaux. Ils seront analysés pour trouver des pistes audio." },
+ ["Scan Now"] = new() { ["en"] = "Scan Now", ["fr"] = "Scanner maintenant" },
+ ["No folders added yet."] = new() { ["en"] = "No folders added yet.", ["fr"] = "Aucun dossier ajouté." },
+ ["Choose the color theme for the application."] = new() { ["en"] = "Choose the color theme for the application.", ["fr"] = "Choisissez le thème de couleur de l'application." },
+ ["Backdrop Effect"] = new() { ["en"] = "Backdrop Effect", ["fr"] = "Effet d'arrière-plan" },
+ ["Choose the visual effect applied to the window background."] = new() { ["en"] = "Choose the visual effect applied to the window background.", ["fr"] = "Choisissez l'effet visuel appliqué à l'arrière-plan de la fenêtre." },
+ ["Frame rate for the audio visualizer."] = new() { ["en"] = "Frame rate for the audio visualizer.", ["fr"] = "Fréquence d'images pour le visualiseur audio." },
+ ["No tracks in library."] = new() { ["en"] = "No tracks in library.", ["fr"] = "Aucune piste dans la bibliothèque." },
+
+ // ── Scan status messages ────────────────────────────────
+ ["Scanned {0}/{1} files..."] = new() { ["en"] = "Scanned {0}/{1} files...", ["fr"] = "Analysé {0}/{1} fichiers..." },
+ ["Done. {0} tracks added."] = new() { ["en"] = "Done. {0} tracks added.", ["fr"] = "Terminé. {0} pistes ajoutées." },
+ ["Scan cancelled."] = new() { ["en"] = "Scan cancelled.", ["fr"] = "Analyse annulée." },
+ ["Done. {0} new tracks found."] = new() { ["en"] = "Done. {0} new tracks found.", ["fr"] = "Terminé. {0} nouvelles pistes trouvées." },
+ ["Scanning all folders..."] = new() { ["en"] = "Scanning all folders...", ["fr"] = "Analyse de tous les dossiers..." },
+ ["Unknown folder ({0})"] = new() { ["en"] = "Unknown folder ({0})", ["fr"] = "Dossier inconnu ({0})" },
+
+ // ── Tray ────────────────────────────────────────────────
+ ["Show\tCtrl+Alt+M"] = new() { ["en"] = "Show\tCtrl+Alt+M", ["fr"] = "Afficher\tCtrl+Alt+M" },
+ };
+}
diff --git a/README.md b/README.md
index 8894204..f5e56c3 100644
--- a/README.md
+++ b/README.md
@@ -187,6 +187,32 @@ All application data is stored in `%LOCALAPPDATA%\Audiomatic\`:
dotnet build Audiomatic.sln -c Release
```
+## Development
+
+### Adding a New Language
+
+The app uses a lightweight dictionary-based i18n system (`Audiomatic/Strings.cs`). English and French are included out of the box. To add a new language:
+
+1. **Add translations** in `Strings.cs` — append your language code to each entry in the `Translations` dictionary:
+
+ ```csharp
+ ["Library"] = new() { ["en"] = "Library", ["fr"] = "Bibliothèque", ["de"] = "Bibliothek" },
+ ```
+
+2. **Add the language option** in `MainWindow.xaml.cs` — find the `// Language section` block inside `ShowSettingsFlyout()` and add a line:
+
+ ```csharp
+ AddLanguageOption("de", Strings.T("German"));
+ ```
+
+3. **Add the language name translations** in `Strings.cs` so it displays correctly in every language:
+
+ ```csharp
+ ["German"] = new() { ["en"] = "German", ["fr"] = "Allemand", ["de"] = "Deutsch" },
+ ```
+
+The fallback chain is: requested language → English → raw key. Missing translations for a given key will gracefully fall back to English.
+

## License
diff --git a/installer.iss b/installer.iss
index 2238b8b..092f854 100644
--- a/installer.iss
+++ b/installer.iss
@@ -1,6 +1,6 @@
[Setup]
AppName=Audiomatic
-AppVersion=0.1.0
+AppVersion=0.1.2
AppPublisher=OhMyCode
DefaultDirName={localappdata}\Programs\Audiomatic
DefaultGroupName=Audiomatic