gopluralizecldr

Trying to understand Golang pluralization


I'm trying to understand pluralization in Go. The example from the docs https://godoc.org/golang.org/x/text/message/catalog#hdr-String_interpolation does not work. The method plural.Select does not event exist. It should be plural.Selectf. Note the f at the end.

message.Set(language.English, "You are %d minute(s) late.",
catalog.Var("minutes", plural.Selectf(1, "one", "minute")),
catalog.String("You are %d ${minutes} late."))
p := message.NewPrinter(language.English)
p.Printf("You are %d minute(s) late.", 5)

I found another tutorial here https://phraseapp.com/blog/posts/internationalization-i18n-go/. This code works fine

message.Set(language.English, "You have %d problem",
    catalog.Var("minutes", plural.Selectf(1, "%d", "one", "minute", "other", "minutes")),
    catalog.String("You are %d ${minutes} late."))
printer := message.NewPrinter(language.English)
printer.Printf("You have %d problem", 1)
printer.Println()
printer.Printf("You have %d problem", 3)
printer.Println()

// result
// You are 1 minute late.
// You are 3 minutes late.

Both examples use the advanced string interpolation. Now I'm trying to understand plural.Selectf. What is the first argument 1 doing? Why do I need the second argument %d? I think I understand the rest

"one"  : "minute"
"other": "minutes"

I also saw %[1]d in catalog.String. What does this do?

Thanks a lot! I'm super confused right now.


Solution

  • Here you go!

    The first argument of plural.Selectf is an int. So it can be any valid integer. The second argument is a string. It should be a format verb i.e %d or %s or %f The third argument is an empty interface, could receive any type i.e string, struct, catalog.Message, ..

    Let's take this example,

    func main() {
    
        var (
                msg = plural.Selectf(2, "%d",
                    "=10", "%[1]d task and %[2]d processes remaining!", // interface 1
                    "=1", "%[1]d task and %[2]d processes", // interface 2
                    "other", "%d tasks and %d processes!" // interface 3
                )
                key = "%d task - %d process"
                tag = "en"
            )
    
            lTag := language.MustParse(tag)
            message.Set(lTag, key, msg)
    
            p := message.NewPrinter(language.English)
            p.Printf("%d task - %d process", 1, 10)
    
    }
    

    Here we have created a NewPrinter with language English and set the translation messages with the key %d task(s) remaining! for tag en(short code for English language).

    When p.Printf("%d task - %d process", 1, 3) line executes, the translation mechanism takes the first argument(format specifier) i.e %d task - %d process and checks for the message by comparing with key we set in for en tag. If the key is found, then it processes the message i.e msg.

    Here the Selectfs first argument says that take nth (i.e 2nd in our case) format verb's value from Printf (i.e 10 in the second value for %d) and compare with selector of cases i.e =10 in the case 1 (interface 1). If the comparison is success then returns the processed value i.e 1 task and 10 processes in case 1.

    If the Printf receives values for 2nd %d other than 1 & 10 then it would return the value from case 3 (interface 3)

    And,

    The %[n]d could be used like,

    fmt.Printf("%[2]d %[1]d\n", 11, 22) and it prints 22 11.

    Hope, this helps you.