Binary (or String) interpolation

Hi all,

I would like to interpolate a string or a binary.
I’d like to get: "Some Foo text" or <<"Some Foo text">>
Given X = "Foo" or X = <<"Foo">>

This snippet is working:

X = "Foo",
Result = lists:flatten(io_lib:format("Some ~s text", [X])),

I am wondering if there are more concise way to achieve the same result.

I read about the bit syntax, but can’t make it work.
This is what I tried (which is not working):

X = <<"Foo">>,
Title = <<"Some ",X/utf8," text">>,

Thanks a lot
Cheers!

2 Likes

Try:

X = <<"Foo"/utf8>>,
Title = <<"Some ",X/binary," text">>,

In the future, there may be more convenient ways to do a similar thing.

3 Likes

Though it might be cheaper to keep them as iolists,
["Some “, X, " text”]
or
[<<“Some “>>, X, <<” text”>>]

Most io functions take iolists as input, so the lists:flatten/1 can/should be avoided.

4 Likes

In this context the formatting with placeholders is preferred, as the word order may change in different languages.

I tried removing the flatten and it is indeed working the same :slight_smile:
I tried searching for iolist in the documentation but I cannot find any useful info,
can someone point me where iolist is documented?

Thank you

See the iodata and iolists in table 7.1
https://www.erlang.org/doc/reference_manual/typespec#types-and-their-syntax

Even better is to look at Unicode chardata or charlist

1 Like

Thank you, will do.

I/O lists are the preferred way to concatenate data like this in Erlang. You can easily do dynamic stuff, e.g. ["foo", dynamic(Input), "bar"] which will get rendered properly and efficiently when it leaves the system through a socket, file, standard out etc.

1 Like

This is the real answer. Nice way to take advantage of iolist behavior.

Ok.

I suppose I will ignore translations for now.
I know they will come though, (will search for a gettext library that day, and hopefully one that supports interpolation)

Cheers!

If you use IO lists you get both performance and dynamic content, such as translations. Example:

[?TXT2("Hello", LangCode), $\s, UserName, $!]

Which would generate for e.g. Swedish ["Hej", $\s, "Carlo", $!] which when outputted would be concatenated by the Erlang VM to "Hej Carlo!".

But I am stuck with the order of the list.
In many cases the order of the dynamic and static content changes based on the language.

Example:

English → The user "UUU" has finished the task "TTT".
Deutsch → Der Benutzer "UUU" hat die Aufgabe "TTT" abgeschlossen.

Where UUU and TTT are the dynamic parts.

Or am I missing something here?

Cheers!

I haven’t used gettext at all, but I would think a good translation libraries should have some templating functionality.

English → The user "${USER}" has finished the task "${TASK}"
Deutsch → Der Benutzer "${USER}" hat die Aufgabe "${TASK}" abgeschlossen.

Yeah yeah, pretty sure as well.

This one looks sick:

I’ll stick with iolists for now and see when I’ll need some more advanced stuff

Cheers!

1 Like

FWIW, I created just for fun a lib that does string interpolation:

BTW, I recommend the use of IO lists.

2 Likes

Yeah, it is often I see superfluous iolist_to_binary/1 or lists:flatten/1 calls when they are not necessary in Erlang. It’s a common beginner anti-pattern.

2 Likes

Is the word order the only thing that may change
with language? I used to teach students about
internationalisation, and there’s a long long list
of things.

  • Dates and times are a big one.
    It’s not just that months and days have different
    names in different languages, the whole structure
    of the calendar may be different. What if your
    customer wants dates displayed on the Hindu
    traditional calendar? (In this country there are
    the Gregorian calendar with English words, the
    Gregorian calendar with Maori words, and N versions
    of “the” traditional Maori calendar, with different
    ideas about when to start a new year. You are NOT
    going to be able to format dates on any of the
    traditional calendars with C’s strftime() or its
    analogues in other languages.)
  • Numbers. Different rules for which characters are
    grouping characters and where they go. And of
    course there are different digits. Unicode 13 had
    64 honest-to-goodness sets of digits, not counting
    21 oddballs.
  • Currency. It’s not just formatting, it’s conversion.
    I have free account with OpenExchangeRates.com, but
    that limits how often I can access it. Speaking of
    formatting, there is a fundamental problem with
    relying on C’s locale support. If you want guidance
    for how to display Yuan in Australia, you’re out of
    luck. The C locale model says “if you’re in Australia
    you only deal with Australian dollars, so XXXX you.”
    This really is not the kind of stuff that you can
    reasonably encode in a string.
  • Weights and measures. Obvious. But there are formatting
    differences as well as differences in what the units are.
  • Place names. The same place may have different names
    even in the same country (Wellington vs Pōneke, for
    example). We really need a decent multilingual gazeteer.
1 Like

Yeah.
Indeed making an application truly “international” involves much more than just translate messages.

BTW in Elixir I am using this library GitHub - elixir-cldr/cldr: Elixir implementation of CLDR/ICU
which does a very good job.

Nice one!
Thanks