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