diff --git a/server/player/chat/translate.go b/server/player/chat/translate.go
index 4beae2c16..4c016cdd2 100644
--- a/server/player/chat/translate.go
+++ b/server/player/chat/translate.go
@@ -75,15 +75,15 @@ func (t Translation) Resolve(l language.Tag) string {
 // F takes arguments for a translation string passed and returns a filled out
 // translation that may be sent to players. The number of arguments passed must
 // be exactly equal to the number specified in Translate. If not, F will panic.
+// Arguments passed are converted to strings using fmt.Sprint(). Exceptions are
+// made for argument values of the type TranslationString, Translation and
+// translation, which are resolved based on the Translator's language.
+// Translations used as arguments should not require any parameters.
 func (t Translation) 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{t: t, params: params, fallbackParams: a}
+	return translation{t: t, params: a}
 }
 
 // translation is a translation string with its arguments filled out. Resolve may
@@ -91,9 +91,8 @@ func (t Translation) F(a ...any) translation {
 // Params may be called to obtain the parameters passed in Translation.F.
 // translation implements the fmt.Stringer and error interfaces.
 type translation struct {
-	t              Translation
-	params         []string
-	fallbackParams []any
+	t      Translation
+	params []any
 }
 
 // Resolve translates the TranslationString of the translation to the language
@@ -104,13 +103,21 @@ func (t translation) Resolve(l language.Tag) string {
 
 // Params returns a slice of values that are used to parameterise the
 // translation returned by Resolve.
-func (t translation) Params() []string {
-	return t.params
+func (t translation) Params(l language.Tag) []string {
+	params := make([]string, len(t.params))
+	for i, arg := range t.params {
+		if str, ok := arg.(TranslationString); ok {
+			params[i] = str.Resolve(l)
+			continue
+		}
+		params[i] = fmt.Sprint(arg)
+	}
+	return params
 }
 
 // String formats and returns the fallback value of the translation.
 func (t translation) String() string {
-	return fmt.Sprintf(text.Colourf(t.t.format, t.t.fallback), t.fallbackParams...)
+	return fmt.Sprintf(text.Colourf(t.t.format, t.t.fallback), t.params...)
 }
 
 // Error formats and returns the fallback value of the translation.
diff --git a/server/session/command.go b/server/session/command.go
index b2c24702b..644a94d73 100644
--- a/server/session/command.go
+++ b/server/session/command.go
@@ -19,14 +19,14 @@ func (s *Session) SendCommandOutput(output *cmd.Output, l language.Tag) {
 	for _, message := range output.Messages() {
 		om := protocol.CommandOutputMessage{Success: true, Message: message.String()}
 		if t, ok := message.(translation); ok {
-			om.Message, om.Parameters = t.Resolve(l), t.Params()
+			om.Message, om.Parameters = t.Resolve(l), t.Params(l)
 		}
 		messages = append(messages, om)
 	}
 	for _, err := range output.Errors() {
 		om := protocol.CommandOutputMessage{Message: err.Error()}
 		if t, ok := err.(translation); ok {
-			om.Message, om.Parameters = t.Resolve(l), t.Params()
+			om.Message, om.Parameters = t.Resolve(l), t.Params(l)
 		}
 		messages = append(messages, om)
 	}
@@ -41,7 +41,7 @@ func (s *Session) SendCommandOutput(output *cmd.Output, l language.Tag) {
 
 type translation interface {
 	Resolve(l language.Tag) string
-	Params() []string
+	Params(l language.Tag) []string
 }
 
 // sendAvailableCommands sends all available commands of the server. Once sent, they will be visible in the
diff --git a/server/session/text.go b/server/session/text.go
index fa59b189e..f1fe077c5 100644
--- a/server/session/text.go
+++ b/server/session/text.go
@@ -24,7 +24,7 @@ func (s *Session) SendTranslation(t chat.Translation, l language.Tag, a []any) {
 		TextType:         packet.TextTypeTranslation,
 		NeedsTranslation: true,
 		Message:          tr.Resolve(l),
-		Parameters:       tr.Params(),
+		Parameters:       tr.Params(l),
 	})
 }