From 1460b2dda3bcd3d3b6ae1b0b8c636c775cfe5628 Mon Sep 17 00:00:00 2001 From: Sandertv Date: Fri, 20 Dec 2024 16:57:04 +0100 Subject: [PATCH] chat/translate.go: Concept implementation of client-side translations. --- server/player/chat/chat.go | 12 ++++++++++ server/player/chat/subscriber.go | 4 ++++ server/player/chat/translate.go | 40 ++++++++++++++++++++++++++++++++ server/session/session.go | 1 + 4 files changed, 57 insertions(+) create mode 100644 server/player/chat/translate.go diff --git a/server/player/chat/chat.go b/server/player/chat/chat.go index 867948790..9a5638925 100644 --- a/server/player/chat/chat.go +++ b/server/player/chat/chat.go @@ -40,6 +40,18 @@ func (chat *Chat) WriteString(s string) (n int, err error) { return len(s), nil } +func (chat *Chat) Writet(t Translation) { + chat.m.Lock() + defer chat.m.Unlock() + for _, subscriber := range chat.subscribers { + if translator, ok := subscriber.(Translator); ok { + translator.Messaget(t) + continue + } + subscriber.Message(t.String()) + } +} + // Subscribe adds a subscriber to the chat, sending it every message written to // the chat. In order to remove it again, use Chat.Unsubscribe(). func (chat *Chat) Subscribe(s Subscriber) { diff --git a/server/player/chat/subscriber.go b/server/player/chat/subscriber.go index c68a91a15..f8e899636 100644 --- a/server/player/chat/subscriber.go +++ b/server/player/chat/subscriber.go @@ -17,6 +17,10 @@ type Subscriber interface { Message(a ...any) } +type Translator interface { + Messaget(t Translation) +} + // StdoutSubscriber is an implementation of Subscriber that forwards messages // sent to the chat to the stdout. type StdoutSubscriber struct{} diff --git a/server/player/chat/translate.go b/server/player/chat/translate.go new file mode 100644 index 000000000..27145ec1a --- /dev/null +++ b/server/player/chat/translate.go @@ -0,0 +1,40 @@ +package chat + +import ( + "fmt" + "github.com/df-mc/dragonfly/server/internal/sliceutil" +) + +var JoinMessage = translate("%multiplayer.player.joined", 1, "%v joined the game") +var QuitMessage = translate("%multiplayer.player.left", 1, "%v left the game") + +func translate(format string, params int, fallback string) Translatable { + return Translatable{format: format, params: params, fallback: fallback} +} + +type Translatable struct { + format string + params int + fallback string +} + +func (t Translatable) F(a ...any) Translation { + if len(a) != t.params { + panic(fmt.Sprintf("translation '%v' requires exactly %v parameters, got %v", t.format, t.params, len(a))) + } + params := make([]string, len(a)) + for i, arg := range a { + params[i] = fmt.Sprint(arg) + } + return Translation{format: t.format, fallback: t.fallback, params: params} +} + +type Translation struct { + format string + fallback string + params []string +} + +func (t Translation) String() string { + return fmt.Sprintf(t.fallback, sliceutil.Convert[any](t.params)...) +} diff --git a/server/session/session.go b/server/session/session.go index 3b94c6b62..c5bd2d87a 100644 --- a/server/session/session.go +++ b/server/session/session.go @@ -256,6 +256,7 @@ func (s *Session) close(tx *world.Tx, c Controllable) { s.chunkLoader.Close(tx) if s.quitMessage != "" { + chat.Global.Writet(chat.QuitMessage.F(s.conn.IdentityData().DisplayName)) _, _ = fmt.Fprintln(chat.Global, text.Colourf("%v", fmt.Sprintf(s.quitMessage, s.conn.IdentityData().DisplayName))) } chat.Global.Unsubscribe(c)