From 2a6443ae3caf00fdfd50057ca7674526edd1ddff Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Mon, 6 Jul 2026 16:22:15 +0700 Subject: [PATCH 1/3] Show Lexbox instead of Language Forge/Depot in send/receive UI. User-facing labels, aliases, and error messages now say Lexbox while server URLs and internal settings keys remain on languageforge.org. Co-authored-by: Cursor --- src/Chorus.Tests/UI/Sync/SyncDialogTests.cs | 12 ++++++------ src/Chorus/UI/Misc/ReadinessPanel.cs | 2 +- src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs | 4 ++-- src/Chorus/UI/Settings/SettingsView.resx | 2 +- src/LibChorus/Model/InternetCloneSettingsModel.cs | 2 +- src/LibChorus/Model/ServerSettingsModel.cs | 6 +++--- src/LibChorus/VcsDrivers/Mercurial/HgExceptions.cs | 2 +- src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs | 6 +++--- src/LibChorus/VcsDrivers/RepositoryAddress.cs | 2 +- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Chorus.Tests/UI/Sync/SyncDialogTests.cs b/src/Chorus.Tests/UI/Sync/SyncDialogTests.cs index 07eb1da21..1da989621 100644 --- a/src/Chorus.Tests/UI/Sync/SyncDialogTests.cs +++ b/src/Chorus.Tests/UI/Sync/SyncDialogTests.cs @@ -35,7 +35,7 @@ public void ShowSyncDialog_InternetAndNetworkPaths_WindowsStyle() { setup.Repository.SetKnownRepositoryAddresses(new RepositoryAddress[] { - RepositoryAddress.Create("language forge", "https://hg-public.languageforge.org"), + RepositoryAddress.Create("Lexbox", "https://hg-public.languageforge.org"), RepositoryAddress.Create("joe's mac", "\\\\suzie-pc\\public\\chorusTest") }); @@ -58,7 +58,7 @@ public void ShowSyncDialog_InternetAndNetworkPaths() { setup.Repository.SetKnownRepositoryAddresses(new RepositoryAddress[] { - RepositoryAddress.Create("language forge", "https://hg-public.languageforge.org"), + RepositoryAddress.Create("Lexbox", "https://hg-public.languageforge.org"), RepositoryAddress.Create("joe's mac", "//suzie-pc/public/chorusTest") }); @@ -80,9 +80,9 @@ public void LaunchDialog_ExampleForBob() setup.Repository.SetKnownRepositoryAddresses(new RepositoryAddress[] { - RepositoryAddress.Create("language forge", "https://pedro:mypassword@hg-public.languageforge.org"), + RepositoryAddress.Create("Lexbox", "https://pedro:mypassword@hg-public.languageforge.org"), }); - setup.Repository.SetDefaultSyncRepositoryAliases(new[] {"language forge"}); + setup.Repository.SetDefaultSyncRepositoryAliases(new[] {"Lexbox"}); using (var dlg = new SyncDialog(setup.ProjectFolderConfig, SyncUIDialogBehaviors.StartImmediatelyAndCloseWhenFinished, @@ -102,9 +102,9 @@ public void LaunchDialog_GoodForCancelTesting() setup.Repository.SetKnownRepositoryAddresses(new RepositoryAddress[] { - RepositoryAddress.Create("language forge", "https://automatedtest:testing@hg-public.languageforge.org/tpi"), + RepositoryAddress.Create("Lexbox", "https://automatedtest:testing@hg-public.languageforge.org/tpi"), }); - setup.Repository.SetDefaultSyncRepositoryAliases(new[] { "language forge" }); + setup.Repository.SetDefaultSyncRepositoryAliases(new[] { "Lexbox" }); using (var dlg = new SyncDialog(setup.ProjectFolderConfig, SyncUIDialogBehaviors.StartImmediately, diff --git a/src/Chorus/UI/Misc/ReadinessPanel.cs b/src/Chorus/UI/Misc/ReadinessPanel.cs index 0df49eb8a..a745d5924 100644 --- a/src/Chorus/UI/Misc/ReadinessPanel.cs +++ b/src/Chorus/UI/Misc/ReadinessPanel.cs @@ -12,7 +12,7 @@ namespace Chorus.UI.Misc { /// /// Show this control somewhere in the setup UI of your application. - /// It will help people know if the project is ready to use LanguageDepot, and + /// It will help people know if the project is ready to use Lexbox, and /// gives them a button to edit the relevant settings. /// public partial class ReadinessPanel : UserControl diff --git a/src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs b/src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs index 4cc860500..a58e75ebe 100644 --- a/src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs +++ b/src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs @@ -78,7 +78,7 @@ private void InitializeComponent() this._accountLabel.Anchor = System.Windows.Forms.AnchorStyles.Right; this._accountLabel.AutoSize = true; this.l10NSharpExtender1.SetLocalizableToolTip(this._accountLabel, null); - this.l10NSharpExtender1.SetLocalizationComment(this._accountLabel, "This is a username. On Language Depot, it is called a \"login.\""); + this.l10NSharpExtender1.SetLocalizationComment(this._accountLabel, "This is a username. On Lexbox, it is called a \"login.\""); this.l10NSharpExtender1.SetLocalizingId(this._accountLabel, "ServerSettingsControl.Login"); this._accountLabel.Location = new System.Drawing.Point(37, 44); this._accountLabel.Name = "_accountLabel"; @@ -297,7 +297,7 @@ private void InitializeComponent() this._serverLabel.Name = "_serverLabel"; this._serverLabel.Size = new System.Drawing.Size(122, 13); this._serverLabel.TabIndex = 18; - this._serverLabel.Text = "to {0} (Language Depot)"; + this._serverLabel.Text = "to {0} (Lexbox)"; // // _tlpPassword // diff --git a/src/Chorus/UI/Settings/SettingsView.resx b/src/Chorus/UI/Settings/SettingsView.resx index 3b011fad8..662fdfa23 100644 --- a/src/Chorus/UI/Settings/SettingsView.resx +++ b/src/Chorus/UI/Settings/SettingsView.resx @@ -156,6 +156,6 @@ suzie = \\SUZIE-PC\TokPisin For an internet server, include your username and password like this: online = https://JoeSmith:mypassword@hg-public.languageforge.org/tpi -For a free internet repository, visit https://public.languageforge.org +For a free Lexbox internet repository, visit https://public.languageforge.org \ No newline at end of file diff --git a/src/LibChorus/Model/InternetCloneSettingsModel.cs b/src/LibChorus/Model/InternetCloneSettingsModel.cs index cd06a44c5..c51c09ac8 100644 --- a/src/LibChorus/Model/InternetCloneSettingsModel.cs +++ b/src/LibChorus/Model/InternetCloneSettingsModel.cs @@ -94,7 +94,7 @@ public virtual bool SetRepositoryAddress() } else if (name.ToLower().EndsWith(@"languageforge.org")) { - name = @"LanguageForge"; + name = @"Lexbox"; } var address = RepositoryAddress.Create(name, URL); diff --git a/src/LibChorus/Model/ServerSettingsModel.cs b/src/LibChorus/Model/ServerSettingsModel.cs index fd6bf81ff..7de2b7c14 100644 --- a/src/LibChorus/Model/ServerSettingsModel.cs +++ b/src/LibChorus/Model/ServerSettingsModel.cs @@ -365,7 +365,7 @@ public string AliasName return "custom"; } - return $"languageForge.org [{Bandwidth}]"; + return $"Lexbox [{Bandwidth}]"; } } @@ -427,12 +427,12 @@ internal static string DecryptPassword(string decryptMe) /// URL-encoded password to use for the current Send and Receive session. /// /// - /// UrlEncode encodes spaces as "+" and "+" as "%2b". LanguageDepot fails to decode plus-encoded spaces. Encode spaces as "%20" + /// UrlEncode encodes spaces as "+" and "+" as "%2b". Lexbox fails to decode plus-encoded spaces. Encode spaces as "%20" /// public static string EncodedPasswordForSession => WebUtility.UrlEncode(PasswordForSession)?.Replace("+", "%20"); /// - /// URL-encoded language forge username + /// URL-encoded Lexbox username /// public static string EncodedLanguageForgeUser => WebUtility.UrlEncode(Settings.Default.LanguageForgeUser); diff --git a/src/LibChorus/VcsDrivers/Mercurial/HgExceptions.cs b/src/LibChorus/VcsDrivers/Mercurial/HgExceptions.cs index 1b9d141a0..01a3ae878 100644 --- a/src/LibChorus/VcsDrivers/Mercurial/HgExceptions.cs +++ b/src/LibChorus/VcsDrivers/Mercurial/HgExceptions.cs @@ -77,7 +77,7 @@ public override string Message } else if(_targetUri.ToLower().Contains("languageforge")) { - return "Your computer could reach LanguageForge.org, but couldn't communicate with the Chorus server there. Possible causes:\r\n1) The Chorus server on LanguageForge might be temporarily out of order. If it is, try again later/tomorrow. \r\n2) A firewall on your machine or on your network is blocking the communication with LanguageForge.org."; + return "Your computer could reach Lexbox, but couldn't communicate with the Chorus server there. Possible causes:\r\n1) The Chorus server on Lexbox might be temporarily out of order. If it is, try again later/tomorrow. \r\n2) A firewall on your machine or on your network is blocking the communication with Lexbox."; } else { diff --git a/src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs b/src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs index 0f5eb695d..4adc0e1bd 100644 --- a/src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs +++ b/src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs @@ -1037,7 +1037,7 @@ public void LogBasicInfo(IList potentialAddresses) _progress.WriteVerbose($"Local User: {GetUserIdInUse()}"); if (potentialAddresses.Any(a => a is HttpRepositoryPath)) { - _progress.WriteVerbose($"LanguageForge User: {Settings.Default.LanguageForgeUser}"); + _progress.WriteVerbose($"Lexbox User: {Settings.Default.LanguageForgeUser}"); } _progress.WriteVerbose($"Repository URI: {string.Join(Environment.NewLine, potentialAddresses.Select(RepositoryURIForLog))}"); @@ -1519,7 +1519,7 @@ public void SetDefaultSyncRepositoryAliases(IEnumerable aliases) IniSection section = GetDefaultRepositoriesSection(doc); foreach (var alias in aliases) { - section.Set(alias, string.Empty); //so we'll have "LanguageForge =", which is weird, but it's the hgrc style + section.Set(alias, string.Empty); //so we'll have "Lexbox =", which is weird, but it's the hgrc style } doc.SaveAndGiveMessageIfCannot(); @@ -2095,7 +2095,7 @@ public string GetProxyConfigParameterString(string httpUrl) public static string DoWorkOfDeterminingProxyConfigParameterString(string httpUrl, IProgress progress) { /* The hg url itself would be more robust for the theoretical possibility of different - * proxies for different destinations, but some hg servers (notably language depot) require a login. + * proxies for different destinations, but some hg servers (notably Lexbox) require a login. * So we're ignoring what we were given, and just using a known address, for now. */ httpUrl = "http://proxycheck.palaso.org"; diff --git a/src/LibChorus/VcsDrivers/RepositoryAddress.cs b/src/LibChorus/VcsDrivers/RepositoryAddress.cs index 99ef7e939..4b8888392 100644 --- a/src/LibChorus/VcsDrivers/RepositoryAddress.cs +++ b/src/LibChorus/VcsDrivers/RepositoryAddress.cs @@ -68,7 +68,7 @@ public static RepositoryAddress Create(string name,string uri) /// /// Creates a new HttpRepositoryPath or DirectoryRepositorySource. /// - /// examples: SIL Language Depot, My Machine, USB Key, Greg + /// examples: Lexbox, My Machine, USB Key, Greg /// /// examples: https://sil.org/chorus, c:\work, UsbKey, //GregSmith/public/language projects /// Note: does not work for ChorusHub From d02d0228898684180a328be34966c8a0dcf593ca Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Tue, 7 Jul 2026 12:06:59 +0700 Subject: [PATCH 2/3] Simplify Lexbox login label and fix standalone app startup. Show "Log in to Lexbox" without the hostname, initialize L10NSharp for Chorus.exe and SampleApp, and mark server settings dialog tests STA. Co-authored-by: Cursor --- .../UI/Misc/ServerSettingsDialogTests.cs | 9 +++++++++ src/Chorus/Program.cs | 16 ++++++++++++++++ .../UI/Misc/ServerSettingsControl.Designer.cs | 5 ++--- src/Chorus/UI/Misc/ServerSettingsControl.cs | 3 --- src/SampleApp/Program.cs | 13 +++++++++++++ 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/Chorus.Tests/UI/Misc/ServerSettingsDialogTests.cs b/src/Chorus.Tests/UI/Misc/ServerSettingsDialogTests.cs index b4bc9a48b..41ccda9f1 100644 --- a/src/Chorus.Tests/UI/Misc/ServerSettingsDialogTests.cs +++ b/src/Chorus.Tests/UI/Misc/ServerSettingsDialogTests.cs @@ -1,3 +1,5 @@ +using System.Threading; +using System.Windows.Forms; using Chorus.Model; using Chorus.UI.Misc; using NUnit.Framework; @@ -5,8 +7,15 @@ namespace Chorus.Tests.UI.Misc { [TestFixture] + [Apartment(ApartmentState.STA)] public class ServerSettingsDialogTests { + [SetUp] + public void Setup() + { + Application.EnableVisualStyles(); + } + [Test, Ignore("Run by hand only")] public void LaunchDialog_FullAddress() { diff --git a/src/Chorus/Program.cs b/src/Chorus/Program.cs index 4ac628c9b..0306a0f39 100644 --- a/src/Chorus/Program.cs +++ b/src/Chorus/Program.cs @@ -20,6 +20,7 @@ static void Main(string[] args) Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); + SetUpLocalization(); SetUpErrorHandling(); //Xpcom.Initialize(XULRunnerLocator.GetXULRunnerLocation()); @@ -66,6 +67,21 @@ static void Main(string[] args) Application.Exit (); } + private static void SetUpLocalization() + { + // Standalone Chorus.exe has no host app to initialize L10NSharp; use English defaults unless XLF files are deployed. + LocalizationManager.StrictInitializationMode = false; + var installedTranslations = Path.Combine(AppContext.BaseDirectory, "localizations"); + if (Directory.Exists(Path.Combine(installedTranslations, "Chorus"))) + { + var userTranslations = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "SIL", "Chorus"); + Directory.CreateDirectory(userTranslations); + ChorusSystem.SetUpLocalization("en", installedTranslations, userTranslations); + } + } + private static void SetUpErrorHandling() { try diff --git a/src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs b/src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs index a58e75ebe..875628c57 100644 --- a/src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs +++ b/src/Chorus/UI/Misc/ServerSettingsControl.Designer.cs @@ -289,15 +289,14 @@ private void InitializeComponent() this._serverLabel.Anchor = System.Windows.Forms.AnchorStyles.Left; this._serverLabel.AutoSize = true; this.l10NSharpExtender1.SetLocalizableToolTip(this._serverLabel, null); - this.l10NSharpExtender1.SetLocalizationComment(this._serverLabel, "This adds information after the \"Log in\" button. Together, these two strings form" + - " a sentence. {0} is a URL, such as public.languageforge.org"); + this.l10NSharpExtender1.SetLocalizationComment(this._serverLabel, "This adds information after the \"Log in\" button. Together, these two strings form a sentence."); this.l10NSharpExtender1.SetLocalizationPriority(this._serverLabel, L10NSharp.LocalizationPriority.Low); this.l10NSharpExtender1.SetLocalizingId(this._serverLabel, "ServerSettingsControl.ServerInfo"); this._serverLabel.Location = new System.Drawing.Point(111, 10); this._serverLabel.Name = "_serverLabel"; this._serverLabel.Size = new System.Drawing.Size(122, 13); this._serverLabel.TabIndex = 18; - this._serverLabel.Text = "to {0} (Lexbox)"; + this._serverLabel.Text = "to Lexbox"; // // _tlpPassword // diff --git a/src/Chorus/UI/Misc/ServerSettingsControl.cs b/src/Chorus/UI/Misc/ServerSettingsControl.cs index 2f2447aac..4f57da899 100644 --- a/src/Chorus/UI/Misc/ServerSettingsControl.cs +++ b/src/Chorus/UI/Misc/ServerSettingsControl.cs @@ -20,9 +20,6 @@ public ServerSettingsControl() { InitializeComponent(); - // format the string with the server URL. We build our own URL because 'resumable' is not helpful here. - _serverLabel.Text = string.Format(_serverLabel.Text, $"{(ServerSettingsModel.IsPrivateServer ? "private" : "public")}{ServerSettingsModel.LanguageForgeServer}"); - _bandwidth.Items.AddRange(ServerSettingsModel.Bandwidths); } diff --git a/src/SampleApp/Program.cs b/src/SampleApp/Program.cs index fef85c39a..f06246543 100644 --- a/src/SampleApp/Program.cs +++ b/src/SampleApp/Program.cs @@ -2,6 +2,8 @@ using System.IO; using System.Threading; using System.Windows.Forms; +using Chorus; +using L10NSharp; namespace SampleApp { @@ -13,6 +15,17 @@ static void Main() Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); + LocalizationManager.StrictInitializationMode = false; + var installedTranslations = Path.Combine(AppContext.BaseDirectory, "localizations"); + if (Directory.Exists(Path.Combine(installedTranslations, "Chorus"))) + { + var userTranslations = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "SIL", "ChorusSampleApp"); + Directory.CreateDirectory(userTranslations); + ChorusSystem.SetUpLocalization("en", installedTranslations, userTranslations); + } + string dataDirectory = Path.Combine(Path.GetTempPath(), "ChorusSampleApp"); if(Directory.Exists(dataDirectory )) DeleteFolderThatMayBeInUse(dataDirectory); From 762ea684c6ad08c9f77e20c3ff666443141313f1 Mon Sep 17 00:00:00 2001 From: Kevin Hahn Date: Thu, 23 Jul 2026 15:00:36 +0700 Subject: [PATCH 3/3] Address PR feedback on Lexbox branding changes. - Migrate the [ChorusDefaultRepositories] entry when a repository alias is renamed so existing projects keep auto-syncing (regression test added). - Avoid a redundant nested Chorus\Chorus user-translations directory when standalone Chorus.exe sets up localization. - Point the settings help text at https://lexbox.org instead of relying on a redirect from public.languageforge.org. Co-Authored-By: Claude Opus 4.8 --- src/Chorus/Program.cs | 4 +++- src/Chorus/UI/Settings/SettingsView.resx | 2 +- .../VcsDrivers/Mercurial/HgRepository.cs | 13 ++++++++++ .../VcsDrivers/Mercurial/HgRepositoryTests.cs | 24 +++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/Chorus/Program.cs b/src/Chorus/Program.cs index 0306a0f39..600eadb9e 100644 --- a/src/Chorus/Program.cs +++ b/src/Chorus/Program.cs @@ -74,9 +74,11 @@ private static void SetUpLocalization() var installedTranslations = Path.Combine(AppContext.BaseDirectory, "localizations"); if (Directory.Exists(Path.Combine(installedTranslations, "Chorus"))) { + // Pass the app's settings root; SetUpLocalization appends "Chorus" itself, so passing + // "SIL" (not "SIL\Chorus") avoids a redundant nested Chorus\Chorus directory. var userTranslations = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - "SIL", "Chorus"); + "SIL"); Directory.CreateDirectory(userTranslations); ChorusSystem.SetUpLocalization("en", installedTranslations, userTranslations); } diff --git a/src/Chorus/UI/Settings/SettingsView.resx b/src/Chorus/UI/Settings/SettingsView.resx index 662fdfa23..398e5fd6a 100644 --- a/src/Chorus/UI/Settings/SettingsView.resx +++ b/src/Chorus/UI/Settings/SettingsView.resx @@ -156,6 +156,6 @@ suzie = \\SUZIE-PC\TokPisin For an internet server, include your username and password like this: online = https://JoeSmith:mypassword@hg-public.languageforge.org/tpi -For a free Lexbox internet repository, visit https://public.languageforge.org +For a free Lexbox internet repository, visit https://lexbox.org \ No newline at end of file diff --git a/src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs b/src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs index 4adc0e1bd..4e3f20e4c 100644 --- a/src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs +++ b/src/LibChorus/VcsDrivers/Mercurial/HgRepository.cs @@ -1498,6 +1498,19 @@ public void SetTheOnlyAddressOfThisType(RepositoryAddress address) if(match!=null) { addresses.Remove(match); + // If the alias name changed (e.g. because the default server was rebranded), migrate the + // matching entry in [ChorusDefaultRepositories] as well. Default-sync membership is matched + // by alias name, so leaving the old name behind would silently drop this repository from + // default sync operations. + if (match.Name != address.Name) + { + var defaultSyncAliases = GetDefaultSyncAliases(); + if (defaultSyncAliases.Remove(match.Name)) + { + defaultSyncAliases.Add(address.Name); + SetDefaultSyncRepositoryAliases(defaultSyncAliases); + } + } } addresses.Add(address); SetKnownRepositoryAddresses(addresses); diff --git a/src/LibChorusTests/VcsDrivers/Mercurial/HgRepositoryTests.cs b/src/LibChorusTests/VcsDrivers/Mercurial/HgRepositoryTests.cs index 88363ddbd..59fb8f697 100644 --- a/src/LibChorusTests/VcsDrivers/Mercurial/HgRepositoryTests.cs +++ b/src/LibChorusTests/VcsDrivers/Mercurial/HgRepositoryTests.cs @@ -152,5 +152,29 @@ public void RemoveCredentialsFromIniIfNecessary_PreservesOtherData(string savedU } } } + + [Test] + public void SetTheOnlyAddressOfThisType_AliasRenamed_MigratesDefaultSyncEntry() + { + const string oldAlias = "languageForge.org [High bandwidth]"; + const string newAlias = "Lexbox [High bandwidth]"; + const string url = "https://hg-public.languageforge.org/tpi"; + + using (var tempDir = new TemporaryFolder("HgRepoDefaultSync")) + { + var repo = new HgRepository(tempDir.Path, _progress); + Directory.CreateDirectory(Path.GetDirectoryName(repo.GetPathToHgrc())); + repo.SetTheOnlyAddressOfThisType(new HttpRepositoryPath(oldAlias, url, false)); + repo.SetDefaultSyncRepositoryAliases(new[] { oldAlias }); + + // SUT: rename the alias (same address type, e.g. server rebranding) + repo.SetTheOnlyAddressOfThisType(new HttpRepositoryPath(newAlias, url, false)); + + var defaultAliases = repo.GetDefaultSyncAliases(); + Assert.That(defaultAliases, Does.Contain(newAlias), "default sync entry should follow the renamed alias"); + Assert.That(defaultAliases, Does.Not.Contain(oldAlias), "stale default sync entry should be removed"); + Assert.That(repo.GetRepositoryPathsInHgrc().Select(p => p.Name), Does.Contain(newAlias)); + } + } } } \ No newline at end of file