Gettext_sigils - a sigil for using gettext with less boilerplate and better readability

All good, you’ve been very patient letting me distract this thread a bit. I’ll do some homework and testing and open an issue or discussion on the repo after that.

Thanks for doing this, I think it really helps make localised applications as easy a non-localised ones.

1 Like

Last note before I’d like to wrap this up here and move the discussion to Github:

I just released v0.3.0 with support for pluralization! With this release, it should now covers all the gettext features (that I’m aware of - except maybe custom interpolators :wink:). Feel free to open an issue on GIthub for suggestions or if you encounter any problems.

Thanks a lot for all the feedback and take care! :heart:

5 Likes

Idea: maybe the pluralization does not require any special characters-just use a single string in code and handle pluralization in translations files. This would require another sigil or a modifier to mark a pluralized string.

1 Like

Not sure I understand. Are you suggesting something like this?

~t"#{count} post(s)"N
msgid "%{count} post(s)"
msgid_plural "%{count} post(s)"
msgstr[0] "One post"
msgstr[1] "%{count} posts"

Hmmm, interesting (assuming you can use the same msgid for singular/plural). I could make the || separator optional (or remove this completely).

What do others think?

1 Like

Yes, exactly that. It even makes the actual template cleaner.

That’s a great idea! :smiley: I think I would even get rid of the separator again as this felt a bit hacky from the start. Unless there is a good reason to keep it.

1 Like

You can even use something like gettext_pseudolocalize | Hex to catch the strings that have missing singular/plural forms.

Interesting concept! :slightly_smiling_face: I think your libaray should work as well while using the sigils.

I really like the proposal regarding pluralization because it allows using gettext progressively without changing the msgid:

# no translation
"#{count} error(s)"

# gettext w/o pluralization
~t"#{count} error(s)"

# gettext with pluralization
~t"#{count} error(s)"N
1 Like

Granted, you’re still in the situation of having special characters for pluralization that people might want to use in the message:

~t"#{count} child(ren) (other parenthesized text)"N

The message can be anything and there is nothing special about the string in my example.

The proposal is to use the same string for singular and plural msgid. I just chose to use parentesis so the message (and fallback, if there is no translation) works in both cases (something you would do if there wasn’t pluralization).

Oh, you’re right, I’m sorry

I just released v0.3.1 with the following change:

  • deprecate the use of the separator (||) for pluralization and promotes the use of a shared msgid for singular/plural forms (thanks @dkuku for the idea)

Note: The separator will still work in the v0.3.x release, but it will be removed in v0.4.x (unless there is a good reason to keep it).

1 Like

I just released v0.3.2 with the following fix:

  • don’t expect pluralization separator to be present in application config

I also noticed that there is an issue when using explicit keys in HEEx templates:

# this works
~H"""
<h1>{~t"Hello, #{@name}!"}</h1>
<div>{~t"You have #{@count} notification(s)"N}</div>
""

# this DOES NOT work
~H"""
<h1>{~t"Hello, #{name :: @user.name}!"}</h1>
<div>{~t"You have #{count :: length(@notifications)} notification(s)"N}</div>
"""

The reason for this is that the HEEx engine does not transform assigns on the right side of :: operators, which are usually used for binary modifiers (see Phoenix LiveView source).

See issue #23 for more information. I’m honestly not sure if this is a bug in LiveView that could be fixed or if I made a bad choice using the :: operator for explicit keys.

If anyone with more knowledge than me has some insights, some guidance would be appreciated! :heart:

Would #{count = length(@notifications)} help? I suppose :: is similar enough generating binaries with <<x::y>> but otherwise looked odd to me inside ~t. = would bring other perhaps unwanted connotations so perhaps it’s not ideal either.

I haven’t looked at the implementation yet but I’d think macro should expand so that HEEx just sees RHS, while somehow preserving gettext extraction behavior if possible.

1 Like

Thanks @wojtekmach! I used :: because I liked the similarity to typespecs, but if = just works, I think it is worth to change.

2 Likes

Great, using = works as expected! :slight_smile: I already updated and merged the PR.

I’m sorry for introducing another breaking change, but with these issues ironed out, I think it should soon be a bit more stable :sweat_smile:

I just released v0.4.0 with the following breaking changes:

  • remove deprecated separator-based pluralization and removed the :pluralization option from use GettextSigils sigils config and application config
  • explicit key syntax changes from #{foo :: bar} to #{foo = bar} to support HEEx assigns (thanks @wojtekmach)
  • HEEx assigns in interpolation now use the assign name as interpolation key (@foo => %{foo})

I apologize for introducing another breaking change with this release, but I hope to have a bit more stability now that some major issues have been solved! :folded_hands:

5 Likes

This horse may have left the barn. However, you may consider ~gtxt instead of ‘~t’ for clarity:

# replacing 'gettext()' with '~gtxt()'
~gtxt"Hello, #{user.name}"

As, ~t could mean anything.

Sidenote: I once suggested using sigils in function definitions to replace ‘do’ for Elixir code back in 2017 during the Elixir v.1 “syntax wars”.

archive: This was the syntax I proposed for the next version of Elixir almost a decade ago.

# replacing 'do' with '~>'
# note: 'defm' replaces 'defmodule'
defm areas ~>
# also note: docstrings are bounded by '|: ... :|'
|: Calculates the area of a rectangle given its length and width :|

# function definition: 'area_rect/2'
   def area_rect (length, width) ~>
     length * width
   ... # replaces 'end' 
...  

Notice there are no ‘end’ block delimiters. I had also proposed that ‘’ could replace ‘end’ to close the function or module block. (coughs, clears throat) Maybe someday :thinking: .

@josevalim had some interesting and pragmatic reasons for sticking with the Elixir syntax having fought with the syntax question privately at the language’s inception (see the HN discussion: Elixir is great. I just wish its syntax was more appealing; some of the design c... | Hacker News ).

Nevertheless, I’m happy to see @josevalim now appreciates that sigils can make verbose Elixir code more succinct … and beautiful :slight_smile:

(For more on the Elixir Syntax Wars see here: https://elixirforum.com/t/discussion-about-syntax-preferences-split-posts/3436)

Only uppercase sigils can be multicharacter.

You’re right given AST pragmatics (i.e., parser simplicity). Instead of a separate sigil library, one may need to consider ditching the sigil and just replacing “gettext’ with “gtxt”. We really should move away from single character references in code just on the basis of the ambiguity nightmare these can cause for code maintainers. That’s the kernel of my earlier proposal.

1 Like