Gettext for Elixir - getting serious at compile time

Gettext for Elixir - getting serious at compile time

Faafc04d9e69b73b9f49995fd4c94d4d?s=128

Andrea Leopardi

October 03, 2015
Tweet

Transcript

  1. gettext for elixir getting serious at compile time

  2. None
  3. processes otp supervision trees

  4. vs compile time runtime

  5. gettext is deadly simple at runtime

  6. free } agent supervisor let it crash

  7. andrea @whatyouhide leopardi

  8. None
  9. gettext

  10. i18n b4g l10n internationalization localization boring

  11. <%= translate "greetings.informal" %> # en_US.yml greetings: informal: "hello" context

    # en_TX.yml greetings: informal: "howdy" translation
  12. # in en_TX/LC_MESSAGES/default.po #: lib/greetings.ex:24 msgid "hello" msgstr "howdy" <%=

    gettext "hello" %>
  13. # in en_TX/LC_MESSAGES/default.po #: lib/greetings.ex:24 msgid "hello" msgstr "howdy" <%=

    gettext "hello" %>
  14. # in en_TX/LC_MESSAGES/default.po #: lib/greetings.ex:24 msgid "hello" msgstr "howdy" <%=

    gettext "hello" %>
  15. # in en_TX/LC_MESSAGES/default.po #: lib/greetings.ex:24 msgid "hello" msgstr "howdy" <%=

    gettext "hello" %>
  16. # in en_TX/LC_MESSAGES/default.po #: lib/greetings.ex:24 msgid "hello" msgstr "howdy" <%=

    gettext "hello" %>
  17. developers see plain strings

  18. translators see plain strings

  19. PO files

  20. translator-friendly syntax # Enough with the greetings examples! #: lib/greeter.ex:24

    msgid "hello" msgstr "hola"
  21. tools

  22. gettext elixir-lang /

  23. read translations from po files extract translations from source interpolate

    translations pluralization
  24. read translations from PO files

  25. defmodule Gettext do @translations Gettext.Compiler.po_files() for {msgid, msgstr} <- @translations

    do def gettext_fn(unquote(msgid)) do unquote(msgstr) end end end
  26. defmodule Gettext do @translations Gettext.Compiler.po_files() for {msgid, msgstr} <- @translations

    do def gettext_fn(unquote(msgid)) do unquote(msgstr) end end end
  27. defmodule Gettext do @translations Gettext.Compiler.po_files() for {msgid, msgstr} <- @translations

    do def gettext_fn(unquote(msgid)) do unquote(msgstr) end end end
  28. defmodule Gettext do @translations Gettext.Compiler.po_files() for {msgid, msgstr} <- @translations

    do def gettext_fn(unquote(msgid)) do unquote(msgstr) end end end
  29. defmodule Gettext do @translations Gettext.Compiler.po_files() for {msgid, msgstr} <- @translations

    do def gettext_fn(unquote(msgid)) do unquote(msgstr) end end end
  30. defmodule Unicode do @pairs Unicode.read("data.txt") for {lower, upper} <- @pairs

    do def lower(unquote(upper)) do unquote(lower) end end end
  31. very fast at runtime

  32. move logic away from runtime

  33. compiler friend is your the

  34. extract translations from source

  35. how they do it

  36. printf(_("Hello"))

  37. printf(_("Hello"))

  38. how we do it

  39. MACROS :D

  40. functions that do stuff at compile time

  41. mix gettext.extract calls mix compile --force

  42. defmacro gettext(msgid) do extract(__CALLER__, msgid) quote do ... end end

  43. defmacro gettext(msgid) do extract(__CALLER__, msgid) quote do ... end end

  44. defmacro gettext(msgid) do extract(__CALLER__, msgid) quote do ... end end

    has to be a string
  45. defmacro gettext(msgid) do extract(__CALLER__, msgid) quote do ... end end

    pushes to an agent
  46. defmacro gettext(msgid) do extract(__CALLER__, msgid) quote do ... end end

    has context
  47. actual implementation

  48. zero runtime cost

  49. compiler friend is your the

  50. interpolate translations

  51. gettext "Hello %{name}!", %{name: "Frodo"} case %{name: "Frodo"} do %{name:

    name} -> {:ok, "Hello " <> name} _ -> {:error, :bad_interp} end
  52. gettext "Hello %{name}!", %{name: "Frodo"} case %{name: "Frodo"} do %{name:

    name} -> {:ok, "Hello " <> name} _ -> {:error, :bad_interp} end
  53. easy pluralization support

  54. import MyApp.Gettext ngettext "One attendant", "%{count} attendants", 254 msgid "One

    attendant" msgid_plural "%{count} attendants" msgstr[0] "Uno spettatore" msgstr[1] "%{count} spettatori"
  55. # Arabic def plural("ar", 0), do: 0 def plural("ar", 1),

    do: 1 def plural("ar", 2), do: 2 def plural("ar", n) when rem(n, 100) >= 3 and ... def plural("ar", n) when rem(n, 100) >= 11, ... def plural("ar", _n), do: 5
  56. workflow

  57. define a gettext module defmodule MyApp.Gettext do use Gettext, otp_app:

    :my_app end
  58. write source code import MyApp.Gettext gettext "Hello, world"

  59. extract translations mix gettext.extract

  60. extract translations POT files #: lib/greetings.ex:24 msgid "Hello, world!" msgstr

    ""
  61. merge POT with locales mix gettext.merge priv/gettext --locale en_TX

  62. merge POT with locales #: lib/old_greetings.ex:23 msgid "Hello, world!" msgstr

    "Ciao, mondo!"
  63. merge POT with locales #: lib/greetings.ex:24 msgid "Hello, world!" msgstr

    "Ciao, mondo!"
  64. merge POT with locales #: lib/greetings.ex:24 #, fuzzy msgid "Hello,

    world!" msgstr "Ciao, mondo"
  65. Again

  66. so.

  67. github.com/elixir-lang/gettext

  68. @WHATYOUHIDE