Template wizardry and its cost

Bastiaan Veelo Bastiaan at Veelo.net
Tue Jun 21 09:06:40 UTC 2022


On Tuesday, 21 June 2022 at 02:35:28 UTC, Steven Schveighoffer 
wrote:
> structs can be functors:

That was one of the things I tried, but I missed this bit:

> ```d
>     this(string s1, string s2) { // this is unfortunately 
> necessary
>         _str = s1;
>         _strpl = s2;
>     }
> ```

[...]

> I will say, I find this line... reprehensible ;)

I left my dirty laundry out in the hopes it would trigger you ;-) 
Thanks for the rinse, it looks great!

> But.... I don't see any actual translation happening in the 
> plural/singular form?

That's because the counting needs to be done on the translated 
string. Fixed below.

Thanks Steve, looks like I'll be releasing my first Dub package 
soonish.

-- Bastiaan.

```d
--- app.d
import gettext;
import std.stdio;

void main()
{
     foreach (n; 0 .. 3)
         writeln(tr!("one goose.", "%d geese.")(n));
}

--- gettext.d
import std;

private @safe struct TranslatableString
{
     string _str;
     string get()
     {
         return gettext(_str);
     }
     alias get this;
}
private @safe struct Strplusarg {
     this(string s) {
         fmt = s;
         auto fs = countFormatSpecifiers(fmt);
         assert(fs == 0 || fs == 1, "Invalid number of 
specifiers"); // bonus sanity check
         hasArg = fs == 1;
     }
     string fmt;
     bool hasArg;
}
private @safe struct TranslatableStringPlural
{
     string _str, _strpl;
     this(string s1, string s2) { // this is unfortunately 
necessary
         _str = s1;
         _strpl = s2;
     }
     string opCall(int n)
     {
         auto f = Strplusarg(ngettext(_str, _strpl, n));
         return f.hasArg ? format(f.fmt, n) : f.fmt;
     }
}
template tr(string singular, string plural = null)
{
     static if (plural == null)
         enum tr = TranslatableString(singular);
     else
         enum tr = TranslatableStringPlural(singular, plural);
}

@safe: private:
int countFormatSpecifiers(string fmt) pure
{
     static void ns(const(char)[] arr) {} // the simplest output 
range
     auto nullSink = &ns;
     int count = 0;
     auto f = FormatSpec!char(fmt);
     while (f.writeUpToNextSpec(nullSink))
         count++;
     return count;
}
// Translation happens here:
string gettext(string str)
{
     return str;
}
string ngettext(string singular, string plural, int n)
{
     return n == 1 ? singular : plural;
}
```

0 geese.
one goose.
2 geese.


More information about the Digitalmars-d mailing list