diff --git a/Components/Composer.razor b/Components/Composer.razor
index 0944b54..931ef2d 100644
--- a/Components/Composer.razor
+++ b/Components/Composer.razor
@@ -129,6 +129,17 @@
}
+ @if (!form.IsLocated && GroupId is null && Editing is null)
+ {
+ @* the language the post is written in, as each language names itself *@
+
+ @foreach (var (languageCode, languageName) in Languages.All)
+ {
+
+ }
+
+ }
+
@@ -258,6 +269,10 @@
_ => default
};
+ // a new post starts in the language the persona chose in Settings, else in the reader's
+ string DefaultLanguage => CascadingState.Persona?.Source?.Language is { Length: > 0 } chosen ? chosen
+ : System.Globalization.CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
+
// a new post starts with the visibility the persona chose in Settings
MessageType DefaultVisibility => CascadingState.Persona?.Source?.Privacy switch
{
@@ -270,6 +285,7 @@
{
form.GroupId = GroupId;
form.MessageType = DefaultVisibility;
+ form.Language = DefaultLanguage;
form.QuotedStatusId = Quoting?.Id;
if (Editing is not null)
{
@@ -290,6 +306,8 @@
"unlisted" => MessageType.Unlisted,
_ => MessageType.Public
};
+ // a reply is written in its thread's language, as a rule
+ form.Language = InReplyTo.Language is { Length: 2 } language && Languages.All.Any(l => l.Code == language) ? language : form.Language;
form.HasContentWarning = InReplyTo.SpoilerText is { Length: > 0 };
form.SpoilerText = InReplyTo.SpoilerText;
var mentions = InReplyTo.Mentions.Select(m => m.Acct).Prepend(InReplyTo.Account?.Acct)
@@ -430,14 +448,14 @@
if (result.Data is ScheduledStatus scheduled)
{
Toast.AddResponseSuccess(Localizer["Scheduled for {0}.", scheduled.ScheduledAt.ToLocalTime().ToString(SUtility.dateTimeFormatExt)]);
- form = new() { GroupId = GroupId, MessageType = DefaultVisibility };
+ form = new() { GroupId = GroupId, MessageType = DefaultVisibility, Language = DefaultLanguage };
await OnPublished.InvokeAsync(null);
return;
}
Toast.AddResponseSuccess(form.IsLocated ? Localizer["Located post published."] : Localizer["Published."]);
var published = result.Data as FeedPost;
- form = new() { GroupId = GroupId, MessageType = DefaultVisibility };
+ form = new() { GroupId = GroupId, MessageType = DefaultVisibility, Language = DefaultLanguage };
await OnPublished.InvokeAsync(published);
}
diff --git a/Models/ComposeForm.cs b/Models/ComposeForm.cs
index 2c485ed..62f9bb2 100644
--- a/Models/ComposeForm.cs
+++ b/Models/ComposeForm.cs
@@ -43,6 +43,9 @@ public class ComposeForm
public int PollExpiresIn { get; set; } = 86400;
public bool PollMultiple { get; set; }
+ /// The language the post is written in (ISO 639-1); null leaves it to PrivaPub.
+ public string Language { get; set; }
+
/// The post this one quotes.
public string QuotedStatusId { get; set; }
diff --git a/Services/StatusService.cs b/Services/StatusService.cs
index 5fc2cd9..63787d1 100644
--- a/Services/StatusService.cs
+++ b/Services/StatusService.cs
@@ -54,7 +54,7 @@ namespace decePubClient.Services
Sensitive = form.HasContentWarning,
SpoilerText = form.HasContentWarning ? form.SpoilerText : null,
Visibility = form.Visibility,
- Language = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
+ Language = form.Language ?? CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
ScheduledAt = form.ScheduledAtUtc?.ToString("o", CultureInfo.InvariantCulture),
Poll = form.HasPoll ? new PollForm { Options = [.. form.PollOptions.Select(o => o.Trim()).Where(o => o.Length > 0)], ExpiresIn = form.PollExpiresIn, Multiple = form.PollMultiple } : null,
QuotedStatusId = form.QuotedStatusId
diff --git a/tests/e2e/Actions/ComposerTests.cs b/tests/e2e/Actions/ComposerTests.cs
index 03549a5..618fbb5 100644
--- a/tests/e2e/Actions/ComposerTests.cs
+++ b/tests/e2e/Actions/ComposerTests.cs
@@ -6,7 +6,8 @@ using Microsoft.Playwright;
namespace decePubClient.E2E.Actions
{
- // The composer beyond words: a poll, the persona's own post edited, and a quote, each checked on PrivaPub
+ // The composer beyond words: a poll in a language picked, the persona's own post edited, and a quote, each checked on
+ // PrivaPub
public sealed class ComposerTests(Browser browser)
{
static async Task OpenHome(IPage page)
@@ -39,12 +40,15 @@ namespace decePubClient.E2E.Actions
var choices = page.Locator("[data-poll-editor] input[type=text]");
await choices.Nth(0).FillAsync("tea");
await choices.Nth(1).FillAsync("coffee");
+ // and in the language picked
+ await page.Locator("[data-compose-language]").First.SelectOptionAsync("it");
await page.GetByRole(AriaRole.Button, new() { Name = "Post" }).Last.ClickAsync();
JsonNode latest = null;
Assert.True(await Pasture.Eventually(async () => (latest = await Latest(persona))?["content"]?.GetValue().Contains(text) == true, 15),
"the poll was never published");
made = latest!["id"]!.GetValue();
Assert.Equal(new[] { "tea", "coffee" }, latest["poll"]!["options"]!.AsArray().Select(o => o!["title"]!.GetValue()));
+ Assert.Equal("it", latest["language"]?.GetValue());
await session.AssertGuards();
}, page);
}