How to organize Gettext .pot files in sub-folders?

I’m using Gettext’s dgettext(domain, msgid) function to organize my translation files (referred to as “domains” in the documentation).

I want to go further and also organize the domain files into sub-folders.

Using dgettext("path/domain", msgid) does create gettext/path/domain.pot. It doesn’t create the file in gettext/en/LC_MESSAGES/path/domain.pot or in any of the other locales and also gives this error:

18:35:43.237 [error] Task #PID<0.433.0> started from #PID<0.88.0> terminating
** (Gettext.Plural.UnknownLocaleError) unknown locale "path". If this is a locale you need to handle,
consider using a custom pluralizer module instead of the default
Gettext.Plural. You can read more about this on the Gettext docs at

    (gettext) lib/gettext/plural.ex:658: Gettext.Plural.recall_if_country_or_raise/2
    (elixir) lib/keyword.ex:603: Keyword.put_new_lazy/3
    (gettext) lib/gettext/merger.ex:163: Gettext.Merger.new_po_file/5
    (gettext) lib/mix/tasks/gettext.merge.ex:184: anonymous fn/5 in Mix.Tasks.Gettext.Merge.merge_dirs/5
    (elixir) lib/task/supervised.ex:89: Task.Supervised.do_apply/2
    (elixir) lib/task/supervised.ex:38: Task.Supervised.reply/5

    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Function: &:erlang.apply/2
    Args: [#Function<2.80905071/1 in Mix.Tasks.Gettext.Merge.merge_dirs/5>, ["priv/gettext/default.pot"]]

I have a mix task that I run when generating .pot files:
translate: ["gettext.extract", "gettext.merge priv/gettext"]

So, is it possible to organize .pot files in sub-folders as I’m trying to do ?

It looks like the error you’re seeing is due to path being in the directory in place of a valid locale. By default you should house the .pot file in priv/gettext/domain.pot and the .po files in priv/gettext/locale/LC_MESSAGES/domain.po.

1 Like

.pot files live in the priv/gettext folder

.po files live in the locales folders (eg. for EN locale: priv/gettext/en/LC_MESSAGES)

So, these equivalences are created (example given only for the EN locale):

  • priv/gettext/default.pot -> priv/gettext/en/LC_MESSAGES/default.po
  • priv/gettext/errors.pot -> priv/gettext/en/LC_MESSAGES/errors.po

A standard Phoenix project has default.pot and errors.pot by default.

What I want to do, if possible, is to organize them in sub-folders, let’s say:

  • a priv/gettext/nav folder holding: header.pot, sidebar.pot, footer.pot

Right now all the .pot files are at the priv/gettext level.

Is it possible to organize them in further sub-folders as in my priv/gettext/nav example ? How should I go about this ?

Your file structure looks fine now. I think you can probably run mix gettext.extract although I haven’t tried it myself with such a file structure. Let me know if it doesn’t work and I can play around on my machine to see if I can come up with something.

That’s what I tried, using a path (subfolder/domain) instead of directly giving the domain as the 1st argument for dgettext function, but it doesn’t work that way, thus my opening post.

Has anyone managed to organize his domain (.pot) files into sub-folders ? Or we’re limited to domain files all being located directly in priv/gettext folder level ?

@sfusato Yes it is possible. For example you can house a .pot file in priv/gettext/foo/bar.pot and the .po files in priv/gettext/foo/locale/LC_messages/bar.po and then exact and merge via mix gettext.extract && mix gettext.merge priv/gettext/foo using dgettext("foo/bar", "string to translate").

Here is an example repo where the translated strings are in lib/gettext_example_web/controllers/page_controller.ex:

Personally I would probably just get creative with my domain naming and keep the default file structure. nav_sidebar in your case, for example.

1 Like

@A-Legg Thank you for taking the time to show me this. This is what I was looking for.