Some Thoughts On String Interpolation [l10n, restricting access, AA]

Adam D Ruppe destructionator at gmail.com
Thu Oct 26 15:34:52 UTC 2023


On Thursday, 26 October 2023 at 11:18:46 UTC, kdevel wrote:
> **Localization**
>
> A few days ago this example was posted in the "Learn" group [1]:
>
> ```d
> writeln(i"You drink $coffees cups a day and it gives you 
> $(coffees + iq) IQ");
> ```
>
> A German version would read
>
> ```d
> writeln(i"Sie trinken $coffees Tassen Kaffee am Tag. Dadurch 
> erhöht sich Ihr IQ auf $(coffees + iq).");
> ```
>
> How could the language version be selected (at runtime)? BTW: 
> Is there a "D way of localization"?

With gnu gettext, you'd first pass the string through a tr() 
function, which lets it swap out at runtime. (You'd have to 
remember to do this though, since writeln will accept a generic 
string without this step.... unless writeln itself started 
wrapping through a standard translator function... but that's 
another story.)

I wrote a sample for the interpolated version here, but the 
translations might not be obvious. Let me add your example as a 
concrete thing.

https://github.com/adamdruppe/interpolation-examples/blob/master/04-internationalization.d

It is now added there, running that program (at the time of this 
writing) gives:


I, Adam, have a singular apple.
I, Adam, have a singular apple.
I, Adam, have 5 apples.
I, Adam, have 5 apples.
GG Adam
GG Adam
ggs 5, Adam
ggs 5, Adam
You drink 5 cups a day and it gives you -25 IQ
Sie trinken 5 Tassen Kaffee am Tag. Dadurch erhöht sich Ihr IQ 
auf -25.



Note that the translator could also change word order, it uses 
positional params here. (I'm not entirely happy with this 
specific syntax but it is just a demo to show that you can do all 
these things.)


> **Restricting Access**
>
> What about
>
> ```d
> writeln(i"You drink $coffees cups a day and it gives you 
> $(password) IQ");
> ```
>
> How is it prevented that the person doing the localization puts 
> arbitrary variable or code references into the localized 
> strings?

The localization thing is done at runtime and only has access to 
the variables passed to it.

If a programmer wrote "it gives you $password" then yes, password 
would be available to the translator, same as any other argument, 
but just... don't do that?

Notice how in the example linked above, the translator uses $1 
and $2 rather than the variable name, since that string is 
handled by the library code, not the D language.


> **Accessing Fields Of A Struct**
> would this work out-of-the-box?:

Yes, of course, exactly the same as if you passed `"name", value` 
to the function. (That's literally what the compiler's rewrite 
does.)

> **Accessing Elements Of An AA**
> writeln (i"The name in s is $(aa[\"name\"])"

This is wrong though, it should be:

writeln (i"The name in s is $(aa["name"])"

Once you're inside the  $(..) region, it is read as D code, not 
as part of a string. (This is pretty standard for language 
support of interpolation.) So you don't want extra \ in there.

I'll add these two to basics.

> That typing is laborious. Isn't there a way to bind the 
> expression to the keys of the AA?

I don't know what this means.

> **Nesting**
> Should it nest? How deep? What is the syntax?

It does and and deep as you want. Remember, what's inside the $() 
is D code, not string, so you'd do:

i"thing $(i"thing $(i"thing"))"

etc. The processing function has the info it needs to support 
this but may have to do extra work with it.

BTW you don't have to ask me, you can ask the compiler, this is 
all fully implemented already. 
https://github.com/dlang/dmd/pull/15715

But let me add a few of these to the examples repo.... and done

https://github.com/adamdruppe/interpolation-examples/blob/master/01-basics.d

shows all these. If you compile the dmd from the PR you can build 
and run all these examples yourself.


More information about the Digitalmars-d mailing list