Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

positional arguments not working #101

Closed
scarf005 opened this issue Dec 3, 2024 · 1 comment
Closed

positional arguments not working #101

scarf005 opened this issue Dec 3, 2024 · 1 comment

Comments

@scarf005
Copy link

scarf005 commented Dec 3, 2024

Please describe your issue

given this .po:

msgid "%s"
msgstr "Hello, %s!"

msgid "%1$s %2$s"
msgstr "First: %1$s, Second: %2$s"

msgid "%2$s then %1$s"
msgstr "Second arg: %2$s followed by first arg: %1$s"

msgid "%1$s is %1$s"
msgstr "Same value repeated: %1$s and %1$s"

msgid "There are %1$d providers available for %2$s:"
msgstr "%2$s에 사용할 수 있는 %1$d개 공급자가 있습니다:"

expected:

Smoke test: Hello, World!
Basic: First: Hello, Second: World
Reversed order: Second arg: Second followed by first arg: First
Repeated positional argument: Same value repeated:Same and Same
Actual: Amazon에 사용할 수 있는 3개 공급자가 있습니다:

actual:

Smoke test: Hello, World!
Basic: First: %!$(string=Hello)s, Second: %!$(string=World)s
Reversed order: Second arg: %!$(string=First)s followed by first arg: %!$(string=Second)s
Repeated positional argument: Same value repeated: %!$(string=Same)s and %!$(MISSING)s
Actual: %!$(int= 3)s에 사용할 수 있는 %!$(string=Amazon)d개 공급자가 있습니다:

Is this a bug, an improvement, a proposal or something else? Describe it.

go.mod:

module gotext-repro

go 1.21

require github.com/leonelquinteros/gotext v1.5.2

require golang.org/x/text v0.3.8 // indirect

main.go:

package main

import (
	"fmt"

	"github.com/leonelquinteros/gotext"
)

func main() {
	// Set PO content with positional arguments
	str := []byte(`
msgid "%s"
msgstr "Hello, %s!"

msgid "%1$s %2$s"
msgstr "First: %1$s, Second: %2$s"

msgid "%2$s then %1$s"
msgstr "Second arg: %2$s followed by first arg: %1$s"

msgid "%1$s is %1$s"
msgstr "Same value repeated: %1$s and %1$s"

msgid "There are %1$d providers available for %2$s:"
msgstr "%2$s에 사용할 수 있는 %1$d개 공급자가 있습니다:"
`)
	// Create Po object
	po := gotext.NewPo()
	po.Parse(str)

	fmt.Println("Smoke test:", po.Get("%s", "World"))
	fmt.Println("Basic:", po.Get("%1$s %2$s", "Hello", "World"))
	fmt.Println("Reversed order:", po.Get("%2$s then %1$s", "First", "Second"))
	fmt.Println("Repeated positional argument:", po.Get("%1$s is %1$s", "Same"))
	fmt.Println("Actual:", po.Get("There are %1$d providers available for %2$s:", 3, "Amazon"))
}

What's the expected behaviour, the current behaviour and the steps to reproduce it?

as specified in https://www.gnu.org/software/gettext/manual/gettext.html#c_002dformat, positional arguments like "Only %2$d bytes free on '%1$s'." should be supported.

Comments

found while testing Jguer/yay#2537

@leonelquinteros
Copy link
Owner

Hi, thank you for reporting this issue.

Initially, I think this is related to how gettext support is implemented on each language. The doc you linked is specific to C language's printf function.
As you can see in the same doc, the following sections describe how string formatting is performed in other languages.

The same doc also contains this sections:

The language’s library should have a string formatting facility. Additionally:
There must be a way, in the format string, to denote the arguments by a positional number or a name. This is needed because for some languages and some messages with more than one substitutable argument, the translation will need to output the substituted arguments in different order. See Special Comments preceding Keywords.

15.3 The Translator’s View
The translator works exactly as in the C language case. The only difference is that when translating format strings, she has to be aware of the language’s particular syntax for positional arguments in format strings.

So, to the point, support to positional arguments in formatted strings is given by Go's fmt package, with the syntax documented here: https://pkg.go.dev/fmt#hdr-Explicit_argument_indexes

Explicit argument indexes
In Printf, Sprintf, and Fprintf, the default behavior is for each formatting verb to format successive arguments passed in the call. However, the notation [n] immediately before the verb indicates that the nth one-indexed argument is to be formatted instead. The same notation before a '*' for a width or precision selects the argument index holding the value. After processing a bracketed expression [n], subsequent verbs will use arguments n+1, n+2, etc. unless otherwise directed.

For example,

fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
will yield "22 11", while

fmt.Sprintf("%[3]*.[2]*[1]f", 12.0, 2, 6)
equivalent to

fmt.Sprintf("%6.2f", 12.0)
will yield " 12.00". Because an explicit index affects subsequent verbs, this notation can be used to print the same values multiple times by resetting the index for the first argument to be repeated:

fmt.Sprintf("%d %d %#[1]x %#x", 16, 17)
will yield "16 17 0x10 0x11".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants