Home / Alt manpages / ngettext(1)

  • ngettext(1)
  • User command
  • linux

Pick Singular or Plural Text with ngettext

English speakers hard-code "if count is 1" until a translated string needs three plural forms, which is the job ngettext was built for. This guide gets you to a shell command that selects singular or plural text from a gettext message catalogue, plus a reliable way to pick the catalogue and check the result. The examples use GNU gettext-runtime 0.21, supplied here by Ubuntu package gettext-base version 0.21-14ubuntu2.

Allow about ten minutes. You need a shell and the ngettext command. This guide only reads existing catalogues: it does not create, edit or install translations, and none of the examples need elevated privileges.

1. Check the installed command

Confirm which executable will run and record its version:

$ command -v ngettext
/usr/bin/ngettext
$ ngettext --version
ngettext (GNU gettext-runtime) 0.21

Checkpoint

If the command is missing, stop here and install the package through your normal system administration process. Do not work around a missing catalogue by changing system files.

2. Give ngettext both message forms and a count

The basic form is ngettext MSGID MSGID-PLURAL COUNT. The first two arguments are the source singular and plural messages, and the count tells gettext which grammatical form to request:

$ printf '%s\n' "$(ngettext 'one file' 'many files' 1)"
one file
$ printf '%s\n' "$(ngettext 'one file' 'many files' 2)"
many files
  • No automatic newline. The command writes the selected message but does not add a newline; the surrounding printf makes terminal output and log lines readable.
  • Command substitution strips trailing newlines too. If a translated message ends in one, use a direct redirection instead when preserving exact output matters.
  • No catalogue, no translation. With no matching catalogue, GNU gettext falls back to the message text on the command line. That makes the example reproducible in the default C locale, it is not evidence a translation was found.

3. Understand what the count actually does

Do not hard-code an English rule such as "only 1 is singular" around a translated message. The catalogue's language supplies the plural rules, and a language can have more than two plural forms, so the same count can select a different form elsewhere.

For a quick local check, these counts select the plural fallback in the installed command:

$ ngettext 'one file' 'many files' 0
many files$ ngettext 'one file' 'many files' -1
many files

The output runs together because ngettext never appends a newline. The important boundary is the argument COUNT, not text parsing. Pass the number you are actually describing and let the active catalogue apply its own language-specific rule.

Checkpoint

If a script needs to test success, save the status immediately after the command. A successful status only means the lookup completed, it does not guarantee a non-empty or translated string came back.

4. Select the message catalogue

A text domain identifies the catalogue, commonly by application or package. Set it explicitly with -d when a script should not depend on the caller's environment:

$ printf '%s\n' "$(ngettext --domain=my-app 'one report' 'many reports' 3)"
many reports

This example uses a domain name but no installed my-app catalogue, so the output is the untranslated fallback. The long option is useful in scripts because its purpose is visible right beside the value.

The positional form works too:

$ printf '%s\n' "$(ngettext my-app 'one report' 'many reports' 1)"
one report

If the domain is omitted, ngettext reads TEXTDOMAIN from the environment. Catalogue lookup normally uses /usr/share/locale; set TEXTDOMAINDIR when the catalogue lives elsewhere. Both variables only select where to look, they do not generate translations.

5. Add context when the same words mean different things

Use -c or --context when one source phrase needs separate translations in different situations. The context becomes part of the lookup key, so it has to match the context used when the catalogue was built:

$ printf '%s\n' "$(ngettext --context=menu 'Open' 'Open' 1)"
Open

This machine has no matching application catalogue for that example, so it prints the source singular text. Context does not select a translation by itself, and changing it will not repair a missing or badly installed catalogue.

Keep message IDs stable. Changing the singular text, plural text, domain or context can make an existing translation unreachable until the catalogue is regenerated.

6. Handle escape sequences on purpose

By default, backslash sequences come back as plain text. The -e option expands the escape sequences documented for this command, including \n for a newline:

$ ngettext -e 'one\nfile' 'many\nfiles' 1
one
file

Use -e only when escape expansion is genuinely part of the message contract, it is easy to make a translated backslash sequence change meaning unexpectedly. The -E option is accepted for compatibility and is ignored, so it does not turn expansion on.

7. Diagnose the common failures

  • Output still in English? Check the domain, locale and catalogue directory first, then confirm the catalogue actually contains the exact singular, plural and context keys. A fallback message is not an error, it is the expected behaviour when no translation exists.
  • Output joined to the next prompt or log line? Add a newline at the output boundary, for example with printf '%s\n' "$(...)". Do not assume ngettext supplied one.

For syntax and version details, use the installed help and version output:

$ ngettext --help
$ ngettext --version
ngettext (GNU gettext-runtime) 0.21

There is no undo step for any of this. These commands read catalogues and environment variables without touching files, services or persistent system state.

Done means

  • Argument order right: you supplied singular text, plural text and a count in that order.
  • Plural logic understood: you know plural selection comes from the active language catalogue, not a shell-side English rule.
  • Domain set deliberately: you set it explicitly when the caller's TEXTDOMAIN should not matter.
  • Context used correctly: only when the catalogue was produced with the same context.
  • Output handled cleanly: you dealt with the missing newline and used -e only on purpose.