Resources
This page has been automatically translated using the Google Translate API services. We are working on improving texts. Thank you for your understanding and patience.
If we internationalize everything, we end up with rules that stifle freedom and innovation. Myron Scholes
Resources are data necessary for the application but do not reside in the executable area. In other words, they are not directly accessible through the program variables, but must be preloaded to be able to use them. The most common are the texts and the images used in the user interface, although any type of file can become a resource (sounds, fonts, 3d models, html pages, etc). To illustrate its use with a real example, we are going to use the application Die
(Figure 1), included in /src/demo/die
.

1. Resource types
- Texts: Although it is very easy to include texts in the code as variables of C, in practice this is not advisable for two reasons: The first is that, normally, it is not the programmers who write the messages that the program shows. By separating them into a separate file, other team members can review and edit them without having to access the code directly. The second reason is internationalization. It is an almost indispensable requirement today to be able to change the language of the program and this may involve several members of the team, as well as the fact that several text strings will refer to the same message. Therefore, extracting them from the source code will be almost indispensable.
- Images: It is not usual for the icons of the program to change according to the language, although this may be the case. The tricky thing here is to transform a .jpg or .png file into a C variable (Listing 1). You have to serialize the file and paste it into the code, something very tedious and difficult for the programmer to maintain. It is preferable to have the images in a separate folder and access them at runtime.
- Files: Apart from text and images, any file can become a resource. In this case, the application will receive a block of bytes with the contents thereof, which must know how to interpret.
1 2 3 4 5 6 |
2. Create resources
If we go to the source directory of the application (C:\nappgui\die
), we see that there is a folder called res
added by CMake when creating the project. Inside there are several icons logo.*
and a license.txt
in which you must write the license with which you are going to distribute the program. A copy of this file will be included in the final package Installers.
You can also see a folder named /res/all
that was not created by CMake, but added later when writing the program. This subfolder is considered a resource bundle and will contain a set of texts, images or files that will be loaded "in block" at some point during execution. We can create as many packages as necessary depending on the size and logic of our program.
In big applications, organize your resources in such a way that it is not necessary to load them all when the application starts. Certain resources may only be required when the user performs an action.
You will see that within /res/all
there is a strings.msg
whose content is shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* Die strings */
TEXT_FACE Face
TEXT_PADDING Padding
TEXT_CORNER Corner
TEXT_RADIUS Radius
TEXT_ONE One
TEXT_TWO Two
TEXT_THREE Three
TEXT_FOUR Four
TEXT_FIVE Five
TEXT_SIX Six
TEXT_TITLE Die Simulator
TEXT_INFO Move the sliders to change the parametric representation of the die face.
TEXT_LANG Language
TEXT_ENGLISH English
TEXT_SPANISH Spanish
|
It also contains the cards.png
image and the spain.png
and usa.png
icons (Figure 2).

src/die/res/all
.Each line within the strings.msg
file defines a new message consisting of an identifier (eg TEXT_FACE
) followed by the text that will be displayed in the program (Face in this case). Text is considered from the first non-blank character after the identifier to the end of the line. It is not necessary to put it in quotation marks ("Face"
) as in C:
|
BILLY Billy "the Kid" was an American Old West outlaw. OTHER Other text. |
Neither do you have to use escape sequences, with the sole exception of '\n'
for multiline messages:
|
TWO_LINES This is the first line\nAnd this is the second. |
The identifier of the message follows the rules of the C identifiers, except that the letters must be uppercase:
|
_ID1 Ok 0ID2 Wrong!! id3 Wrong!! ID3 Ok |
The messages accept any Unicode character. We can divide the texts into so many files *.msg
as necessary and should be stored in UTF8 format.
Visual Studio does not save the files in UTF8 by default. Make sure you do it at each*.msg
contains non-US-ASCII characters.File->Save As->Save with encoding-> Unicode (UTF8 Without Signature) - Codepage 65001
.
3. Internationalization (i18n)
We have used English as the main language of the program. Now we are going to include a translation into the Spanish language. To do this, we return to the /res/all
folder, where we see the /es_es
subdirectory that contains another strings.msg
file. The identifiers in this file are the same as in /all/strings.msg
but the texts are in another language. Depending on the selected language, the program will use one version or another.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* Die strings */
TEXT_FACE Cara
TEXT_PADDING Margen
TEXT_CORNER Borde
TEXT_RADIUS Radio
TEXT_ONE Uno
TEXT_TWO Dos
TEXT_THREE Tres
TEXT_FOUR Cuatro
TEXT_FIVE Cinco
TEXT_SIX Seis
TEXT_TITLE Simulador de dado
TEXT_INFO Mueve los sliders para cambiar la representación paramétrica de la cara del dado.
TEXT_LANG Idioma
TEXT_ENGLISH Inglés
TEXT_SPANISH Español
|
We must take into account some simple rules when locating resources:
- If the local version of a resource does not exist, the global version of it will be used. CMake will warn if there are untranslated texts Resource warnings.
- Those resources only present in localized folders will be ignored. It is imperative that the global version exists.
- No "subpackets" of resources are allowed. Only two levels will be processed:
/res/pack
for the global and/res/pack/local
for those localized. - The existing resources in the root folder (
/res
) will be ignored. All resources must be linked to a package. - The localized texts must have the same identifier as their global corresponding. Otherwise, different messages are considered.
- To create the localized version of an image or another file, include it in its corresponding localized folder (eg
/es/all/es_es/cards.png
) using the same file name as the global version. - To name the localized folders, use the two-letter language code ISO 639-1 (en, es, fr, de, zh, ...) and, optionally, the two-letter country code ISO-3166 (en_us, en_gb, ...).
4. Runtime translation
After pressing [Generate]
, for each resource bundle, CMake creates a *.h
with the same name as the folder: all.h
in this case (Listing 4). This file contains the resource identifiers, as well as a function that allows us to access them all_respack()
. In (Listing 5) we see the actions to take to use these resources in our program.
all.h
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
/* Automatic generated by NAppGUI Resource Compiler (nrc-r1490) */ #include "core.hxx" __EXTERN_C /* Messages */ extern ResId TEXT_FACE; extern ResId TEXT_PADDING; extern ResId TEXT_CORNER; extern ResId TEXT_RADIUS; extern ResId TEXT_ONE; extern ResId TEXT_TWO; extern ResId TEXT_THREE; extern ResId TEXT_FOUR; extern ResId TEXT_FIVE; extern ResId TEXT_SIX; extern ResId TEXT_TITLE; extern ResId TEXT_INFO; extern ResId TEXT_LANG; extern ResId TEXT_ENGLISH; extern ResId TEXT_SPANISH; /* Files */ extern ResId CARDS_PNG; extern ResId SPAIN_PNG; extern ResId USA_PNG; ResPack *all_respack(const char_t *local); __END_C |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include "all.h" gui_respack(all_respack); gui_language(""); ... label_text(label1, TEXT_FACE); imageview_image(vimg, CARDS_PNG); ... static void i_OnLang(App *app, Event *e) { const EvButton *params = event_params(e, EvButton); const char_t *lang = params->index == 0 ? "en_us" : "es_es"; gui_language(lang); unref(app); } |
- Line 1 includes the resource package header (Listing 4), which has been generated automatically by CMake.
- Line 3 registers the package in Gui, the library in charge of the graphic interface. If the application had more resource packages we would add them in the same way.
- Line 4 sets the default language (English).
- Lines 6 and 7 assign a text and an image to two controls respectively. The identifiers are defined in
"all.h"
, as we have just seen. - Line 13 translates the entire interface in response to a change in control PopUp (Figure 3).

Basically, a call to gui_language, involves coordinating three actions:
- Load localized resources and replace them with current ones.
- Assign new texts and images to all program controls and menus.
- Resize windows and menus, since changing text and images will influence the size of controls.
5. Editing resources
To add new resource files or delete any of the existing ones, we just have to go to the folder res/all
through the file browser and do it there directly. The message files *.msg
can be edited from Visual Studio, since CMake includes them within the IDE (Figure 4). After making any changes to the resource folder or editing a file *.msg
, we must press [Generate]
in CMake so that these modifications can be integrated into the project. After each update, the identifiers of the new resources will be created and those whose associated resource will have disappeared will be eliminated, which will produce compilation errors that will facilitate the correction of the code.

6. Manual management
Although the usual will be to delegate the management of resources in the library gui
, it is possible to access the content of the packages directly, as we see in (Listing 6).
1 2 3 4 5 6 7 8 |
#include "all.h" ResPack *pack = all_respack("es_es"); ... label_text(label1, respack_text(pack, TEXT_FACE)); imageview_image(vimg, respack_image(pack, CARDS_PNG)); ... respack_destroy(&pack); |
- Line 1 includes the resource package header.
- Line 3 creates an object with the content of the package in Spanish language. Each resource package will provide its own constructor, whose name will begin with that of its folder
xxxx_
respack(). - Lines 5 and 6 get a text and an image respectively to assign them to the interface controls.
- Line 8 destroys the resource package, at the end of its use.
There is a big difference between allocating resources through ResId
or by functions respack_
(Listing 7). In the first case, the label control will be "sensitive" to the language changes made by gui_language. However, in cases 2 and 3 a constant text has been assigned to the control, which will not be affected by this function. We will be responsible for changing the text, if necessary.
1 2 3 |
label_text(label1, TEXT_FACE); label_text(label1, respack_text(pack, TEXT_FACE)); label_text(label1, "Face"); |
The choice of one or the other access mode will depend on the requirements of the program. We remind you that in order to carry out the automatic translations, resources must be registered with gui_respack.
7. Resource processing
Let's see in a little more detail how NAppGUI generates the resource modules. When establishing NRC_EMBEDDED
in the command desktopApp()
, we tell CMake to process the resources of the Die project. We can also choose the option NRC_PACKED
of which we will speak next. When we press [Generate]
CMake traverses the subfolders within the directory res
of each project, calling the nrc utility (NAppGUI Resource Compiler) (Figure 5). This program is in the folder prj/scripts
of the distribution of the SDK. For each resource package, nrc creates two source files (one .c
and a .h
) and links them to the project. The .h
contains the identifiers and the constructor that we have seen in (Listing 4). For its part, the .c
performs the package implementation based on the content of each folder and the nrcMode
modality.

Files created by nrc are considered generated code and are not saved in the foldersrc
but in the folderbuild
. They will be updated every time you press[Generate]
in CMake, regardless of the platform on which we are working. On the contrary, the original resource files (located in the folderres
) are considered part of the source code.
8. Resource distribution
In the previous chapter, when creating the Visual Studio solution, we indicated that we had to use the constant NRC_EMBEDDED
in the sentence desktopApp()
inside the file CMakeLists.txt
. There are two other modalities more related to the management of resources and that can be configured separately within each command desktopApp()
:
NRC_NONE
: CMake will ignore the contents of the folderres
, except for the icon of the application. No resource packages will be generated even if there is content within this folder.NRC_EMBEDDED
: The resources, with all their translations, are integrated as part of the executable (Figure 6). It is a very interesting option for applications of small or medium size, since in a single file*.exe
we will supply the entire program. You will not need an installer and we will have the certainty that the software will not fail due to the lack of an external file. The downside is that, obviously, the size of the executable will grow considerably so it is not advisable in programs with many resources, very heavy, or with a multitude of translations.NRC_PACKED
: For each resource package, a*.res
file will be created external to the executable that will be loaded and released at runtime as needed (Figure 7). The advantages of this method are the disadvantages of the previous one and vice versa: Smaller executables, but with external dependencies (the own ones.res
) that must be distributed together. The use of memory will also be optimized, being able to load the*.res
on demand.


CMake manages the location of the resource packages for us. In Windows and Linux applications, it will copy all *.res
in the executable directory. In macOS it will place them in the folder resources
of the bundle. A very important fact is that we do not have to modify the source code when going from one modality to another. nrc is already responsible for managing the load according to the type of package. Something logical can be to start with NRC_EMBEDDED
, and if the project grows, change to NRC_PACKED
. We just have to press again [Generate]
(as we always do) and recompile the project so that the change becomes effective.
In Windows and Linux files*.res
they must always be installed in the same directory as the executable. In the case of macOS, CMake generates a bundle ready for distribution and installs the resource packages in the directory/resources
of said bundle.
9. Resource warnings
nrc is a silent script whose work is integrated into CMake's build process, going unnoticed in most cases. But there are times that it detects anomalies in the resource directories and it must inform us in some way. In these cases, a red line will appear in the CMake console indicating the project and affected package(s) (Figure 8). The details dumps in the file NRCLog.txt
located in the generated resources folder (CMake shows the complete path).

If the failures are critical, nrc will not be able to generate the *.h
and *.c
associated to the package, preventing the application from being compiled (in essence it does not stop being a compilation error). Other times they are mere warnings that should be fixed, but they allow you to continue compiling. Specifically, the critical errors that affect nrc are the following: (we show them in English as they are written in NRCLog.txt
).
- MsgError (%s:%d): Comment not closed (%s).
- MsgError (%s:%d): Invalid TEXT_ID (%s).
- MsgError (%s:%d): Unexpected end of file after string ID (%s).
- Duplicate resource id in '%s' (%s).
- Can't load resource file '%s'.
- Error reading '%s' resource directory.
- Error reading '%s' subdirectories.
- Error creating '%s' header file.
- Error creating '%s' source file.
- Error creating '%s' packed file.
Por otro lado, los avisos no-críticos:
- Empty message file '%s'.
- Ignored localized text '%s' in '%s'. Global resource doesn't exists.
- Ignored localized file '%s' in '%s'. Global resource doesn't exists.
- There is no localized version of the text '%s' in '%s'.
- Localized directory '%s' is empty or has invalid resources.
10. Application icon
When we create a new project, CMake establishes a default icon for the application, which it places in the directory /res
, with the name logo*
. This image will be "embedded" in the executable and the operating system will use it to represent the application on the desktop (Figure 9). Windows and Linux also use it in the title bar of the window. We have three versions:
- logo256.ico: Version for Windows Vista and later. They should include the resolutions: 256x256, 48x48, 32x32 and 16x16.
- logo48.ico: Version for Linux and Visual Studio 2008 and 2005, which do not support resolutions of 256x256. This version only includes: 48x48, 32x32 and 16x16.
- logo.icns: Version for macOS. Resolutions 512x512, 256x256, 128x128, 32x32 and 16x16 both in normal resolution (@1x) and Retina Display (@2x).

CMake is already responsible for using the appropriate version of the icon according to the platform we are compiling. To change the default icon, open the files logo*
with some graphic editor (Figure 10), make the changes and press again [Generate]
in CMake. Very important: do not change the names of the files, they should always be logo256.ico
, logo48.ico
and logo.icns
.

logo.ico
.