Build multi-language support into your Linux application with catgets

Translator

© Photo by Leonardo Toshiro Okubo on Unsplash

© Photo by Leonardo Toshiro Okubo on Unsplash

Article from Issue 266/2023
Author(s):

To make programs useful to a worldwide audience, you need to build in support for multiple languages. Catgets is a tool that helps you reach beyond your mother tongue.

One way that programmers can help others use their software is to add multi-language support. I'm not talking about programming languages; I mean spoken languages. For example, you may have written your open source program to print information and error messages in English, but what if your user speaks only Spanish? Does your open source program also "speak" Spanish? What about German, French, Italian, and all the other languages spoken around the world?

To make programs truly useful, programmers should support internationalization. An easy way to do that is with the catgets library [1], the original Unix method for a program to retrieve messages and other strings in the user's preferred spoken language. The GNU library also includes a similar function called gettext, which uses a different lookup method. Whereas catgets uses three values to look up a message (the catalog, the message set, and the message number), gettext uses the message itself as the lookup value.

Catgets provides an interface to fetch strings from a special file called a catalog [2] that contains all the messages your program needs to print. The basic usage is to open the catalog, fetch messages from the catalog and print them, and then close the catalog.

Opening and Closing a Catalog

Before you can use a message catalog, you first need to open it. The catopen() function opens a message catalog and returns a catalog descriptor, which is similar to a file pointer. You'll use this descriptor when you retrieve messages later using catgets(). The function call to catgets() asks for the filename of a message catalog, plus a flag that indicates if catgets() should use the current language locale value. If the flag is set to NL_CAT_LOCALE, then catgets() will use the current language locale, which you might set with setlocale(). Otherwise, catgets() will use the value from the LANG environment variable.

#include <nl_types.h>
nl_catd catopen(const char *catalog,int flag);

The catalog indicates the message catalog you want to open. If this contains a path, then catopen() will open that file. If not, then catopen() will look for the message catalog file in the directories specified with the NLSPATH environment variable.

Programs can open multiple catalogs at once, such as one catalog for error messages, another for debugging information, and so on. Each new message catalog requires a separate call to catopen() to open the catalog and get a descriptor. But most programs typically use just one message catalog file and divide the messages into message sets. I recommend using just one message catalog unless your program is really big and needs to organize a lot of different messages.

For example, to open a message catalog file called hello.cat, you would use catopen() as follows:

nl_catd cat;
cat = catopen("./hello.cat",NL_CAT_LOCALE);

The catopen() function returns the catalog descriptor as type nl_catd, or -1 to indicate an error.

When you don't need the message catalog anymore, you can close it with the catclose() function:

#include <nl_types.h>
int catclose(nl_catd cat);

Fetching Messages with catgets

To print a message to the user in the user's preferred spoken language, you first need to retrieve a string from the catalog. The catgets() function looks up the message from the database using three telltales: the catalog, the message set, and the message number within the message set. catgets() then returns a pointer to the string from the catalog, as follows:

#include <nl_types.h>
char *catgets(nl_catd cat, int set,int num, const char *message);

If catgets() can't find the message number in the message set in the message catalog, it returns a default string. By using a string as one of the function arguments, your program will always have a fallback message to print. This also makes your code more readable, because your catgets() call contains the string it needs to look up.

For instance, let's say your program needs to print the string "Hello" to the user. To look up this message from the catalog, you need to know two things: what is the message set this message is defined in, and what is the message number in the message set. If "Hello" is the first string in the second message set, you might use catgets() as follows to retrieve the string from the catalog and print it:

char msg;
msg = catgets(cat, 2, 1, "Hello");
puts(msg);

Creating a Message Catalog

A message catalog is a kind of database file that contains all the messages for your program. But you don't create the binary file by hand. Instead, you write a plain text file using a custom syntax and a few special markers, and then use a program to convert the text file into a catalog database file. In this way, the catalog text file is basically the "source code" for your catalog database file.

In the source file, keywords start with a dollar sign. For example, $set defines the start of a new message set, such as $set 2 for the second message set.

A dollar sign followed immediately by a space or tab indicates a comment. Translators might use these comments to make note of who last updated the file, and what each string is supposed to mean. Blank lines are ignored.

To demonstrate how to define a message catalog file, I'll define a message catalog for a sample program. For fun, I'll define a few program messages in a made-up language, Klingon, so that you can easily recognize if the program is correctly looking up messages from the catalog or printing the "fallback" messages from the call to the catgets() function. You might create a message catalog that defines a few strings such as Yes and No, and any other messages a program might need to print such as greeting the user and asking important questions (Listing 1).

Listing 1

A sample message catalog

 

When the file is complete, you can turn it into a message catalog with the gencat command [3]. For example, the following command converts the input file hello.klingon into a catalog file called hello.cat:

$ gencat -o hello.cat hello.klingon

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Palm Responds to App Catalog Critics

    Palm has announced that it will simplify its developer program for the Linux-based Web OS behind its new Palm Pre smartphone. The device maker is thereby responding to hefty criticism about its App Catalog.

  • Decision Making Scripts

    The Bash shell uses different criteria to make decisions. Learn how to teach your shell scripts to make the right choice.

  • Hypermail

    Hypermail converts email messages to HTML and allows you to group your messages in tidy archives.

  • Beagle

    To find files, music, messages, and photos in a single search, try this desktop tool with the power of an Internet search engine.

  • QR Code Generators

    With the right tools, you can create your own QR code squares with information you want to share, for example, on a business card, in a letter, or on your website.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News