From 2bf3ecdbbe2e21704e9045f3a3cd8888b02d7694 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rado=C5=A1=20Mili=C4=87ev?= <40705899+rammba@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:32:30 +0100 Subject: [PATCH 1/4] Add Serbian cyrillic language --- src/.build/lessmsi.msbuild | 4 + src/LessMsi.Gui/LessMsi.Gui.csproj | 1 + .../Resources/Languages/Strings.sr-Cyrl.resx | 303 ++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 src/LessMsi.Gui/Resources/Languages/Strings.sr-Cyrl.resx diff --git a/src/.build/lessmsi.msbuild b/src/.build/lessmsi.msbuild index 839c849..b7203a9 100644 --- a/src/.build/lessmsi.msbuild +++ b/src/.build/lessmsi.msbuild @@ -104,6 +104,10 @@ fi + + + sr-Cyrl + diff --git a/src/LessMsi.Gui/LessMsi.Gui.csproj b/src/LessMsi.Gui/LessMsi.Gui.csproj index a4f1896..0364fdc 100644 --- a/src/LessMsi.Gui/LessMsi.Gui.csproj +++ b/src/LessMsi.Gui/LessMsi.Gui.csproj @@ -168,6 +168,7 @@ + diff --git a/src/LessMsi.Gui/Resources/Languages/Strings.sr-Cyrl.resx b/src/LessMsi.Gui/Resources/Languages/Strings.sr-Cyrl.resx new file mode 100644 index 0000000..f8b1199 --- /dev/null +++ b/src/LessMsi.Gui/Resources/Languages/Strings.sr-Cyrl.resx @@ -0,0 +1,303 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + О програму + + + Додај пречицу у Explorer + + + Додаје ставке 'Издвоји' и 'Истражи' у контекстни мени при десном клику на .msi датотеке + + + Све датотеке + + + Путања до датотеке је неисправно формирана + + + Промени језик + + + Завршено + + + Компонента + + + &Копирај + + + Опис: + + + Директоријум + + + &Уреди + + + Путања до датотеке је празна + + + ГРЕШКА + + + &Излаз + + + И&здвоји + + + Издвоји датотеке + + + Издвајање + + + Издвајање датотеке + + + Издвоји stream датотеке... + + + Датотека + + + Датотека '{0}' не постоји + + + &Датотека + + + датотека пронађено. + + + Није могуће пронаћи stream за CAB '{0}' + + + ID + + + Иницијализација + + + Путања до датотеке садржи невалидне карактере + + + Грешка при учитавању информација о резимеу + + + Учитавање листе табела... + + + Датотека недостаје + + + .msi датотеке + + + Назив + + + Нема доступних датотека + + + &Отвори + + + Неуспешно отварање датотеке + + + Подешавања + + + &Подешавања + + + Обрада табеле '{0}'. + + + Недавне датотеке + + + Уклони ставку пречице + + + Уклања контекстни мени ако постоји + + + треба да буде у истом директоријуму као + + + Претражи: + + + Претражи датотеку + + + Изабери &све + + + Молимо изаберите неке или све датотеке да бисте их издвојили. + + + Величина + + + Stream + + + Stream-ови + + + Резиме + + + &Табела + + + Приказ табеле + + + Путања до датотеке је предугачка + + + Тип + + + Распакивање + + + По&ништи избор свега + + + Вредност + + + Верзија + + + Није могуће приказати датотеке + + + Није могуће приказати табелу + + \ No newline at end of file From d78a556a90975cc95d16e50eaa4d26af0e7ae22b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rado=C5=A1=20Mili=C4=87ev?= <40705899+rammba@users.noreply.github.com> Date: Wed, 4 Feb 2026 19:40:19 +0100 Subject: [PATCH 2/4] Add Serbian latin language --- src/.build/lessmsi.msbuild | 4 + src/LessMsi.Gui/LessMsi.Gui.csproj | 1 + .../Resources/Languages/Strings.sr-Latn.resx | 303 ++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 src/LessMsi.Gui/Resources/Languages/Strings.sr-Latn.resx diff --git a/src/.build/lessmsi.msbuild b/src/.build/lessmsi.msbuild index b7203a9..71c143f 100644 --- a/src/.build/lessmsi.msbuild +++ b/src/.build/lessmsi.msbuild @@ -108,6 +108,10 @@ sr-Cyrl + + + sr-Latn + diff --git a/src/LessMsi.Gui/LessMsi.Gui.csproj b/src/LessMsi.Gui/LessMsi.Gui.csproj index 0364fdc..92fe4b4 100644 --- a/src/LessMsi.Gui/LessMsi.Gui.csproj +++ b/src/LessMsi.Gui/LessMsi.Gui.csproj @@ -169,6 +169,7 @@ + diff --git a/src/LessMsi.Gui/Resources/Languages/Strings.sr-Latn.resx b/src/LessMsi.Gui/Resources/Languages/Strings.sr-Latn.resx new file mode 100644 index 0000000..b1e8435 --- /dev/null +++ b/src/LessMsi.Gui/Resources/Languages/Strings.sr-Latn.resx @@ -0,0 +1,303 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + O programu + + + Dodaj prečicu u Explorer + + + Dodaje stavke 'Izdvoji' i 'Istraži' u kontekstni meni pri desnom kliku na .msi datoteke + + + Sve datoteke + + + Putanja do datoteke je neispravno formirana + + + Promeni jezik + + + Završeno + + + Komponenta + + + &Kopiraj + + + Opis: + + + Direktorijum + + + &Uredi + + + Putanja do datoteke je prazna + + + GREŠKA + + + &Izlaz + + + I&zdvoji + + + Izdvoji datoteke + + + Izdvajanje + + + Izdvajanje datoteke + + + Izdvoji stream datoteke... + + + Datoteka + + + Datoteka '{0}' ne postoji + + + &Datoteka + + + datoteka pronađeno. + + + Nije moguće pronaći stream za CAB '{0}' + + + ID + + + Inicijalizacija + + + Putanja do datoteke sadrži nevalidne karaktere + + + Greška pri učitavanju informacija o rezimeu + + + Učitavanje liste tabela... + + + Datoteka nedostaje + + + .msi datoteke + + + Naziv + + + Nema dostupnih datoteka + + + &Otvori + + + Neuspešno otvaranje datoteke + + + Podešavanja + + + &Podešavanja + + + Obrada tabele '{0}'. + + + Nedavne datoteke + + + Ukloni stavku prečice + + + Uklanja kontekstni meni ako postoji + + + treba da bude u istom direktorijumu kao + + + Pretraži: + + + Pretraži datoteku + + + Izaberi &sve + + + Molimo izaberite neke ili sve datoteke da biste ih izdvojili. + + + Veličina + + + Stream + + + Stream-ovi + + + Rezime + + + &Tabela + + + Prikaz tabele + + + Putanja do datoteke je predugačka + + + Tip + + + Raspakivanje + + + Po&ništi izbor svega + + + Vrednost + + + Verzija + + + Nije moguće prikazati datoteke + + + Nije moguće prikazati tabelu + + \ No newline at end of file From d94a98b00460fd1f009d532c16e9f61a81a0b7e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rado=C5=A1=20Mili=C4=87ev?= <40705899+rammba@users.noreply.github.com> Date: Sat, 7 Feb 2026 12:54:43 +0100 Subject: [PATCH 3/4] Handle different versions of the same language Using `new CultureInfo` instead of `CultureInfo.CreateSpecificCulture` Using `CultureInfo.Name` instead of `CultureInfo.TwoLetterISOLanguageName` --- src/LessMsi.Gui/ChangeLanguageForm.cs | 16 +++++----- src/LessMsi.Gui/MainForm.cs | 2 +- src/Lessmsi.Tests/GUITests.cs | 46 ++++++++++++++++++++++++++- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/LessMsi.Gui/ChangeLanguageForm.cs b/src/LessMsi.Gui/ChangeLanguageForm.cs index 8fba8e0..365343d 100644 --- a/src/LessMsi.Gui/ChangeLanguageForm.cs +++ b/src/LessMsi.Gui/ChangeLanguageForm.cs @@ -21,7 +21,7 @@ public ChangeLanguageForm() { InitializeComponent(); - m_CurrentCheckedLang = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; + m_CurrentCheckedLang = Thread.CurrentThread.CurrentUICulture.Name; setGUIData(); @@ -83,26 +83,26 @@ private void generateRadioButtons() radioButtonsPanel.Controls.Clear(); m_RadioButtonDict = new Dictionary(); - string currentTwoLetterLang = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName; + string currentCultureName = Thread.CurrentThread.CurrentUICulture.Name; for (int i = 0; i < m_CultureInfoDict.Count; i++) { - var currentCultureKey = m_CultureInfoDict.ElementAt(i).Key; - var currentCultureInfo = m_CultureInfoDict.ElementAt(i).Value; + var cultureName = m_CultureInfoDict.ElementAt(i).Key; + var cultureInfo = m_CultureInfoDict.ElementAt(i).Value; var radioButton = new RadioButton { - Name = currentCultureKey, - Text = currentCultureInfo.DisplayName, + Name = cultureName, + Text = cultureInfo.DisplayName, AutoSize = true, Margin = new Padding(5), Location = new System.Drawing.Point(10, 25 * i), - Checked = currentTwoLetterLang == currentCultureKey + Checked = currentCultureName == cultureName }; radioButton.CheckedChanged += OnRadioButtonCheckedChanged; - m_RadioButtonDict.Add(currentCultureKey, radioButton); + m_RadioButtonDict.Add(cultureName, radioButton); radioButtonsPanel.Controls.Add(radioButton); } diff --git a/src/LessMsi.Gui/MainForm.cs b/src/LessMsi.Gui/MainForm.cs index c1f8fb1..8282bad 100644 --- a/src/LessMsi.Gui/MainForm.cs +++ b/src/LessMsi.Gui/MainForm.cs @@ -1057,7 +1057,7 @@ private void changeLangToolStripMenuItem_Click(object sender, EventArgs e) string newSelectedLanguage = changeLanguageForm.NewSelectedLanguage; if (newSelectedLanguage != string.Empty) { - Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(newSelectedLanguage); + Thread.CurrentThread.CurrentUICulture = new CultureInfo(newSelectedLanguage); Controls.Clear(); InitializeComponent(); diff --git a/src/Lessmsi.Tests/GUITests.cs b/src/Lessmsi.Tests/GUITests.cs index a1a7ba4..5f3b762 100644 --- a/src/Lessmsi.Tests/GUITests.cs +++ b/src/Lessmsi.Tests/GUITests.cs @@ -15,6 +15,8 @@ public void CheckUIStrings() { checkEnglishUIStrings(); checkItalianUIStrings(); + checkSerbianCyrillicUIStrings(); + checkSerbianLatinUIStrings(); } private void checkEnglishUIStrings() @@ -59,12 +61,54 @@ private void checkItalianUIStrings() revertToOriginalLocale(); } + private void checkSerbianCyrillicUIStrings() + { + setCustomLocale("sr-Cyrl"); + + var form = new MainForm(string.Empty); + + // test if form was created successfully + Assert.NotNull(form); + + // check buttons strings + Assert.Equal("Изабери &све", form.btnSelectAll.Text); + Assert.Equal("По&ништи избор свега", form.btnUnselectAll.Text); + Assert.Equal("И&здвоји", form.btnExtract.Text); + + // check strip menu items strings + Assert.Equal("&Уреди", form.editToolStripMenuItem.Text); + Assert.Equal("&Подешавања", form.preferencesToolStripMenuItem.Text); + + revertToOriginalLocale(); + } + + private void checkSerbianLatinUIStrings() + { + setCustomLocale("sr-Latn"); + + var form = new MainForm(string.Empty); + + // test if form was created successfully + Assert.NotNull(form); + + // check buttons strings + Assert.Equal("Izaberi &sve", form.btnSelectAll.Text); + Assert.Equal("Po&ništi izbor svega", form.btnUnselectAll.Text); + Assert.Equal("I&zdvoji", form.btnExtract.Text); + + // check strip menu items strings + Assert.Equal("&Uredi", form.editToolStripMenuItem.Text); + Assert.Equal("&Podešavanja", form.preferencesToolStripMenuItem.Text); + + revertToOriginalLocale(); + } + private void setCustomLocale(string locale) { originalCulture = CultureInfo.CurrentCulture; originalUICulture = CultureInfo.CurrentUICulture; - var culture = CultureInfo.CreateSpecificCulture(locale); + var culture = new CultureInfo(locale); CultureInfo.CurrentCulture = culture; CultureInfo.CurrentUICulture = culture; } From 2aef0c8f4e2a04d2caa9f8e3083a5ef2369105d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rado=C5=A1=20Mili=C4=87ev?= <40705899+rammba@users.noreply.github.com> Date: Mon, 9 Feb 2026 18:39:02 +0100 Subject: [PATCH 4/4] Properly set language radio button Use CultureInfo.Parent for comparing CultureInfo objects --- src/LessMsi.Gui/ChangeLanguageForm.cs | 5 ++-- .../Extensions/CultureInfoExtensions.cs | 29 +++++++++++++++++++ src/LessMsi.Gui/LessMsi.Gui.csproj | 1 + 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/LessMsi.Gui/Extensions/CultureInfoExtensions.cs diff --git a/src/LessMsi.Gui/ChangeLanguageForm.cs b/src/LessMsi.Gui/ChangeLanguageForm.cs index 365343d..2108379 100644 --- a/src/LessMsi.Gui/ChangeLanguageForm.cs +++ b/src/LessMsi.Gui/ChangeLanguageForm.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Windows.Forms; using System.Collections.Generic; +using LessMsi.Gui.Extensions; namespace LessMsi.Gui { @@ -83,7 +84,7 @@ private void generateRadioButtons() radioButtonsPanel.Controls.Clear(); m_RadioButtonDict = new Dictionary(); - string currentCultureName = Thread.CurrentThread.CurrentUICulture.Name; + var currentCulture = Thread.CurrentThread.CurrentUICulture; for (int i = 0; i < m_CultureInfoDict.Count; i++) { @@ -97,7 +98,7 @@ private void generateRadioButtons() AutoSize = true, Margin = new Padding(5), Location = new System.Drawing.Point(10, 25 * i), - Checked = currentCultureName == cultureName + Checked = currentCulture.BelongsTo(cultureInfo) }; radioButton.CheckedChanged += OnRadioButtonCheckedChanged; diff --git a/src/LessMsi.Gui/Extensions/CultureInfoExtensions.cs b/src/LessMsi.Gui/Extensions/CultureInfoExtensions.cs new file mode 100644 index 0000000..6f97673 --- /dev/null +++ b/src/LessMsi.Gui/Extensions/CultureInfoExtensions.cs @@ -0,0 +1,29 @@ +using System.Globalization; + +namespace LessMsi.Gui.Extensions +{ + public static class CultureInfoExtensions + { + public static bool BelongsTo(this CultureInfo culture, CultureInfo target) + { + if (culture == null || target == null) + { + return false; + } + + var current = culture; + + while (!current.Equals(CultureInfo.InvariantCulture)) + { + if (current.Equals(target)) + { + return true; + } + + current = current.Parent; + } + + return false; + } + } +} diff --git a/src/LessMsi.Gui/LessMsi.Gui.csproj b/src/LessMsi.Gui/LessMsi.Gui.csproj index 92fe4b4..2db0dd1 100644 --- a/src/LessMsi.Gui/LessMsi.Gui.csproj +++ b/src/LessMsi.Gui/LessMsi.Gui.csproj @@ -77,6 +77,7 @@ ChangeLanguageForm.cs + Form