diff --git a/irc/channel.go b/irc/channel.go index 7b680a17..02a01ceb 100644 --- a/irc/channel.go +++ b/irc/channel.go @@ -619,21 +619,21 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I if item.AccountName == "*" { message = fmt.Sprintf(client.t("%s joined the channel"), nick) } else { - message = fmt.Sprintf(client.t("%s [account: %s] joined the channel"), nick, item.AccountName) + message = fmt.Sprintf(client.t("%[1]s [account: %[2]s] joined the channel"), nick, item.AccountName) } rb.Add(tags, "HistServ", "PRIVMSG", chname, message) case history.Part: nick := stripMaskFromNick(item.Nick) - message := fmt.Sprintf(client.t("%s left the channel (%s)"), nick, item.Message.Original) + message := fmt.Sprintf(client.t("%[1]s left the channel (%[2]s)"), nick, item.Message.Original) rb.Add(tags, "HistServ", "PRIVMSG", chname, message) case history.Quit: nick := stripMaskFromNick(item.Nick) - message := fmt.Sprintf(client.t("%s quit (%s)"), nick, item.Message.Original) + message := fmt.Sprintf(client.t("%[1]s quit (%[2]s)"), nick, item.Message.Original) rb.Add(tags, "HistServ", "PRIVMSG", chname, message) case history.Kick: nick := stripMaskFromNick(item.Nick) // XXX Msgid is the kick target - message := fmt.Sprintf(client.t("%s kicked %s (%s)"), nick, item.Msgid, item.Message.Original) + message := fmt.Sprintf(client.t("%[1]s kicked %[2]s (%[3]s)"), nick, item.Msgid, item.Message.Original) rb.Add(tags, "HistServ", "PRIVMSG", chname, message) } } diff --git a/irc/chanserv.go b/irc/chanserv.go index c72059b6..3a12cc07 100644 --- a/irc/chanserv.go +++ b/irc/chanserv.go @@ -149,15 +149,15 @@ func csAmodeHandler(server *Server, client *Client, command string, params []str sort.Slice(affectedModes, func(i, j int) bool { return umodeGreaterThan(affectedModes[i].Mode, affectedModes[j].Mode) }) - csNotice(rb, fmt.Sprintf(client.t("Channel %s has %d persistent modes set"), channelName, len(affectedModes))) + csNotice(rb, fmt.Sprintf(client.t("Channel %[1]s has %[2]d persistent modes set"), channelName, len(affectedModes))) for _, modeChange := range affectedModes { - csNotice(rb, fmt.Sprintf(client.t("Account %s receives mode +%s"), modeChange.Arg, string(modeChange.Mode))) + csNotice(rb, fmt.Sprintf(client.t("Account %[1]s receives mode +%[2]s"), modeChange.Arg, string(modeChange.Mode))) } case modes.Add, modes.Remove: if len(affectedModes) > 0 { csNotice(rb, fmt.Sprintf(client.t("Successfully set mode %s"), change.String())) } else { - csNotice(rb, client.t("Change was a no-op")) + csNotice(rb, client.t("No changes were made")) } } } @@ -293,7 +293,7 @@ func csUnregisterHandler(server *Server, client *Client, command string, params expectedCode := unregisterConfirmationCode(info.Name, info.RegisteredAt) if expectedCode != verificationCode { csNotice(rb, ircfmt.Unescape(client.t("$bWarning: unregistering this channel will remove all stored channel attributes.$b"))) - csNotice(rb, fmt.Sprintf(client.t("To confirm channel unregistration, type: /CS UNREGISTER %s %s"), channelKey, expectedCode)) + csNotice(rb, fmt.Sprintf(client.t("To confirm channel unregistration, type: /CS UNREGISTER %[1]s %[2]s"), channelKey, expectedCode)) return } diff --git a/irc/handlers.go b/irc/handlers.go index 90f345f1..dfbf0ac5 100644 --- a/irc/handlers.go +++ b/irc/handlers.go @@ -166,8 +166,8 @@ func accRegisterHandler(server *Server, client *Client, msg ircmsg.IrcMessage, r } sendSuccessfulRegResponse(client, rb, false) } else { - messageTemplate := client.t("Account created, pending verification; verification code has been sent to %s:%s") - message := fmt.Sprintf(messageTemplate, callbackNamespace, callbackValue) + messageTemplate := client.t("Account created, pending verification; verification code has been sent to %s") + message := fmt.Sprintf(messageTemplate, fmt.Sprintf("%s:%s", callbackNamespace, callbackValue)) rb.Add(nil, server.name, RPL_REG_VERIFICATION_REQUIRED, nick, casefoldedAccount, message) } diff --git a/irc/help.go b/irc/help.go index e2a94e0f..34de5a31 100644 --- a/irc/help.go +++ b/irc/help.go @@ -646,13 +646,13 @@ func GenerateHelpIndex(lm *languages.Manager, forOpers bool) map[string]string { defaultHelpIndex := `= Help Topics = Commands: -%s +%[1]s RPL_ISUPPORT Tokens: -%s +%[2]s Information: -%s` +%[3]s` newHelpIndex := make(map[string]string) diff --git a/irc/hostserv.go b/irc/hostserv.go index 696f942d..ff35a80e 100644 --- a/irc/hostserv.go +++ b/irc/hostserv.go @@ -222,7 +222,7 @@ func hsStatusHandler(server *Server, client *Client, command string, params []st } if account.VHost.ApprovedVHost != "" { - hsNotice(rb, fmt.Sprintf(client.t("Account %s has vhost: %s"), accountName, account.VHost.ApprovedVHost)) + hsNotice(rb, fmt.Sprintf(client.t("Account %[1]s has vhost: %[2]s"), accountName, account.VHost.ApprovedVHost)) if !account.VHost.Enabled { hsNotice(rb, fmt.Sprintf(client.t("This vhost is currently disabled, but can be enabled with /HS ON"))) } @@ -274,9 +274,9 @@ func hsSetHandler(server *Server, client *Client, command string, params []strin func hsWaitingHandler(server *Server, client *Client, command string, params []string, rb *ResponseBuffer) { requests, total := server.accounts.VHostListRequests(10) - hsNotice(rb, fmt.Sprintf(client.t("There are %d pending requests for vhosts (%d displayed)"), total, len(requests))) + hsNotice(rb, fmt.Sprintf(client.t("There are %[1]d pending requests for vhosts (%[2]d displayed)"), total, len(requests))) for i, request := range requests { - hsNotice(rb, fmt.Sprintf(client.t("%d. User %s requests vhost: %s"), i+1, request.Account, request.RequestedVHost)) + hsNotice(rb, fmt.Sprintf(client.t("%[1]d. User %[2]s requests vhost: %[3]s"), i+1, request.Account, request.RequestedVHost)) } } @@ -288,7 +288,7 @@ func hsApproveHandler(server *Server, client *Client, command string, params []s hsNotice(rb, client.t("An error occurred")) } else { hsNotice(rb, fmt.Sprintf(client.t("Successfully approved vhost request for %s"), user)) - chanMsg := fmt.Sprintf("Oper %s approved vhost %s for account %s", client.Nick(), vhostInfo.ApprovedVHost, user) + chanMsg := fmt.Sprintf("Oper %[1]s approved vhost %[2]s for account %[3]s", client.Nick(), vhostInfo.ApprovedVHost, user) hsNotifyChannel(server, chanMsg) for _, client := range server.accounts.AccountToClients(user) { client.Notice(client.t("Your vhost request was approved by an administrator")) diff --git a/irc/nickserv.go b/irc/nickserv.go index f852b73a..6afbfc8e 100644 --- a/irc/nickserv.go +++ b/irc/nickserv.go @@ -392,8 +392,8 @@ func nsRegisterHandler(server *Server, client *Client, command string, params [] sendSuccessfulRegResponse(client, rb, true) } } else { - messageTemplate := client.t("Account created, pending verification; verification code has been sent to %s:%s") - message := fmt.Sprintf(messageTemplate, callbackNamespace, callbackValue) + messageTemplate := client.t("Account created, pending verification; verification code has been sent to %s") + message := fmt.Sprintf(messageTemplate, fmt.Sprintf("%s:%s", callbackNamespace, callbackValue)) nsNotice(rb, message) } } @@ -459,7 +459,7 @@ func nsUnregisterHandler(server *Server, client *Client, command string, params expectedCode := unregisterConfirmationCode(account.Name, account.RegisteredAt) if expectedCode != verificationCode { nsNotice(rb, ircfmt.Unescape(client.t("$bWarning: unregistering this account will remove its stored privileges.$b"))) - nsNotice(rb, fmt.Sprintf(client.t("To confirm account unregistration, type: /NS UNREGISTER %s %s"), cfname, expectedCode)) + nsNotice(rb, fmt.Sprintf(client.t("To confirm account unregistration, type: /NS UNREGISTER %[1]s %[2]s"), cfname, expectedCode)) return } diff --git a/irc/services.go b/irc/services.go index 5947458e..b8a63f1a 100644 --- a/irc/services.go +++ b/irc/services.go @@ -143,12 +143,12 @@ func serviceRunCommand(service *ircService, server *Server, client *Client, cmd } if cmd == nil { - sendNotice(fmt.Sprintf("%s /%s HELP", client.t("Unknown command. To see available commands, run"), service.ShortName)) + sendNotice(fmt.Sprintf(client.t("Unknown command. To see available commands, run: /%s HELP"), service.ShortName)) return } if len(params) < cmd.minParams { - sendNotice(fmt.Sprintf(client.t("Invalid parameters. For usage, do /msg %s HELP %s"), service.Name, strings.ToUpper(commandName))) + sendNotice(fmt.Sprintf(client.t("Invalid parameters. For usage, do /msg %[1]s HELP %[2]s"), service.Name, strings.ToUpper(commandName))) return } diff --git a/languages/example/help.lang.json b/languages/example/help.lang.json index d9253ae8..0bba1219 100644 --- a/languages/example/help.lang.json +++ b/languages/example/help.lang.json @@ -1,5 +1,5 @@ { - "= Help Topics =\n\nCommands:\n%s\n\nRPL_ISUPPORT Tokens:\n%s\n\nInformation:\n%s": "= Help Topics =\n\nCommands:\n%s\n\nRPL_ISUPPORT Tokens:\n%s\n\nInformation:\n%s", + "= Help Topics =\n\nCommands:\n%[1]s\n\nRPL_ISUPPORT Tokens:\n%[2]s\n\nInformation:\n%[3]s": "= Help Topics =\n\nCommands:\n%[1]s\n\nRPL_ISUPPORT Tokens:\n%[2]s\n\nInformation:\n%[3]s", "== Channel Modes ==\n\nOragono supports the following channel modes:\n\n +b | Client masks that are banned from the channel (e.g. *!*@127.0.0.1)\n +e | Client masks that are exempted from bans.\n +I | Client masks that are exempted from the invite-only flag.\n +i | Invite-only mode, only invited clients can join the channel.\n +k | Key required when joining the channel.\n +l | Client join limit for the channel.\n +m | Moderated mode, only privileged clients can talk on the channel.\n +n | No-outside-messages mode, only users that are on the channel can send\n | messages to it.\n +R | Only registered users can talk in the channel.\n +s | Secret mode, channel won't show up in /LIST or whois replies.\n +t | Only channel opers can modify the topic.\n\n= Prefixes =\n\n +q (~) | Founder channel mode.\n +a (&) | Admin channel mode.\n +o (@) | Operator channel mode.\n +h (%) | Halfop channel mode.\n +v (+) | Voice channel mode.": "== Channel Modes ==\n\nOragono supports the following channel modes:\n\n +b | Client masks that are banned from the channel (e.g. *!*@127.0.0.1)\n +e | Client masks that are exempted from bans.\n +I | Client masks that are exempted from the invite-only flag.\n +i | Invite-only mode, only invited clients can join the channel.\n +k | Key required when joining the channel.\n +l | Client join limit for the channel.\n +m | Moderated mode, only privileged clients can talk on the channel.\n +n | No-outside-messages mode, only users that are on the channel can send\n | messages to it.\n +R | Only registered users can talk in the channel.\n +s | Secret mode, channel won't show up in /LIST or whois replies.\n +t | Only channel opers can modify the topic.\n\n= Prefixes =\n\n +q (~) | Founder channel mode.\n +a (&) | Admin channel mode.\n +o (@) | Operator channel mode.\n +h (%) | Halfop channel mode.\n +v (+) | Voice channel mode.", "== Server Notice Masks ==\n\nOragono supports the following server notice masks for operators:\n\n a | Local announcements.\n c | Local client connections.\n j | Local channel actions.\n k | Local kills.\n n | Local nick changes.\n o | Local oper actions.\n q | Local quits.\n t | Local /STATS usage.\n u | Local client account actions.\n x | Local X-lines (DLINE/KLINE/etc).\n\nTo set a snomask, do this with your nickname:\n\n /MODE +s \n\nFor instance, this would set the kill, oper, account and xline snomasks on dan:\n\n /MODE dan +s koux": "== Server Notice Masks ==\n\nOragono supports the following server notice masks for operators:\n\n a | Local announcements.\n c | Local client connections.\n j | Local channel actions.\n k | Local kills.\n n | Local nick changes.\n o | Local oper actions.\n q | Local quits.\n t | Local /STATS usage.\n u | Local client account actions.\n x | Local X-lines (DLINE/KLINE/etc).\n\nTo set a snomask, do this with your nickname:\n\n /MODE +s \n\nFor instance, this would set the kill, oper, account and xline snomasks on dan:\n\n /MODE dan +s koux", "== User Modes ==\n\nOragono supports the following user modes:\n\n +a | User is marked as being away. This mode is set with the /AWAY command.\n +i | User is marked as invisible (their channels are hidden from whois replies).\n +o | User is an IRC operator.\n +R | User only accepts messages from other registered users. \n +s | Server Notice Masks (see help with /HELPOP snomasks).\n +Z | User is connected via TLS.": "== User Modes ==\n\nOragono supports the following user modes:\n\n +a | User is marked as being away. This mode is set with the /AWAY command.\n +i | User is marked as invisible (their channels are hidden from whois replies).\n +o | User is an IRC operator.\n +R | User only accepts messages from other registered users. \n +s | Server Notice Masks (see help with /HELPOP snomasks).\n +Z | User is connected via TLS.", @@ -10,11 +10,13 @@ "AWAY [message]\n\nIf [message] is sent, marks you away. If [message] is not sent, marks you no\nlonger away.": "AWAY [message]\n\nIf [message] is sent, marks you away. If [message] is not sent, marks you no\nlonger away.", "CAP [:]\n\nUsed in capability negotiation. See the IRCv3 specs for more info:\nhttp://ircv3.net/specs/core/capability-negotiation-3.1.html\nhttp://ircv3.net/specs/core/capability-negotiation-3.2.html": "CAP [:]\n\nUsed in capability negotiation. See the IRCv3 specs for more info:\nhttp://ircv3.net/specs/core/capability-negotiation-3.1.html\nhttp://ircv3.net/specs/core/capability-negotiation-3.2.html", "CHANSERV [params]\n\nChanServ controls channel registrations.": "CHANSERV [params]\n\nChanServ controls channel registrations.", + "CHATHISTORY [params]\n\nCHATHISTORY is an experimental history replay command. See these documents:\nhttps://github.com/MuffinMedic/ircv3-specifications/blob/chathistory/extensions/chathistory.md\nhttps://gist.github.com/DanielOaks/c104ad6e8759c01eb5c826d627caf80d": "CHATHISTORY [params]\n\nCHATHISTORY is an experimental history replay command. See these documents:\nhttps://github.com/MuffinMedic/ircv3-specifications/blob/chathistory/extensions/chathistory.md\nhttps://gist.github.com/DanielOaks/c104ad6e8759c01eb5c826d627caf80d", "CS [params]\n\nChanServ controls channel registrations.": "CS [params]\n\nChanServ controls channel registrations.", "DEBUG