10.3. Переводы с помощью autotools
Добавим autotools-поддержку переводов. Поскольку все действия над переводами — шаблонные, нет необходимости задавать собственный po/Makefile.am. Он и финальный po/Makefile целиком генерируются из файлов po/Makevars (с настройкой дополнительных переменных po/Makefile) и po/POTFILES.in (со списком источников сообщений, требующих перевода). Название файла с переводом выбирается автоматически — это код языка + расширение .po, в нашем случае — ru.po.
Файл po/Makevars подойдёт стандартный; в ALT он входит с состав пакета gettext-tools:
@user
[user@VM sheepcounter-pkg] cp /usr/share/gettext/po/Makevars.template po/Makevars
Перевод требуется только для строк в sheepcounter.c:
@user:
sheepcounter-pkg/po/POTFILES.in
src/sheepcounter.c
Классическая структура autotools предполагает отдельный Makefile в каждом компоненте проекта — в базовой директории, в src/ и в /po; для двух из них напишем примитивные Makefile.am:
@user:
sheepcounter-pkg/Makefile.am
SUBDIRS = src po
Макрос PACKAGE попадёт в файл config.h, который создаётся после ./configure. Расположение директории с системной локалью тоже задаётся с помощью configure и доступно в Makefile под именем localedir. В качестве макроса Си LOCALE_PATH мы его определим, как и раньше, самостоятельно — дополнив список параметров компилятора Си, которые ему подсовывает automake:
@user:
sheepcounter-pkg/src/Makefile.am
CFLAGS = -Wall -O0 -g
AM_CFLAGS=-D'LOCALE_PATH="$(localedir)"'
bin_PROGRAMS=sheepcounter
Добавим config.h в список заголовочных файлов нашей программы:
@user:
sheepcounter-pkg/src/sheepcounter.c
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <libintl.h>
#include <locale.h>
#include "config.h"
#define _(STRING) gettext(STRING)
…
…
Добавим сам configure.ac. В нем для локализации указываются зависимости на GNU gettext, языки переводов, а также генерат po/Makefile.in в макросе AC_CONFIG_FILES.
В настройки программы также добавлен параметр для работы с числами, а не только с цифрами. Отслеживается он с помощью ключей --{enable/disable}-numbers. Ключи присваивают макросу значения yes или no соответственно, в зависимости от значения с помощью макроса условия AS_IF производится его определение:
@user:
sheepcounter-pkg/configure.ac
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_INIT([sheepcounter], [1.0], [UsamG1t])
AM_INIT_AUTOMAKE([foreign])
AM_GNU_GETTEXT(external)
AM_GNU_GETTEXT_REQUIRE_VERSION(0.21)
AC_CONFIG_SRCDIR([src/sheepcounter.c])
AC_CONFIG_HEADERS([config.h])
ALL_LINGUAS="ru"
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([libintl.h locale.h stdlib.h])
# Optional clues
AC_ARG_ENABLE([numbers],
AS_HELP_STRING([--enable-numbers],[Enable not only digits counting]),
AS_IF([test "$enable_numbers" = "yes"],
AC_DEFINE(NUMBERS, [], [Numbers counting acception]))
)
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CHECK_FUNCS([realpath setlocale])
AC_FUNC_ERROR_AT_LINE
AC_CONFIG_FILES([Makefile po/Makefile.in src/Makefile])
AC_OUTPUT
.
├── configure.ac
├── Makefile.am
├── po
│ ├── Makevars
│ ├── POTFILES.in
│ └── ru.po
└── src
├── Makefile.am
└── sheepcounter.c
Отредактируем spec-файл (теперь в нём нет необходимости доопределять какие-либо параметры):
@user:
sheepcounter-pkg/.gear/sheepcounter.spec
%def_disable numbers
Name: sheepcounter
Version: 1.0
Release: alt1
Summary: Test pkg with i18n
License: GPL-3.0-or-later
Group: Development/Other
Source0: %name-%version.tar.gz
%description
This is a small testing package, builded with i18n
%prep
%setup
%build
%autoreconf
%configure %{subst_enable numbers}
%make_build
%install
%makeinstall_std
%files
%_bindir/%name
%_datadir/locale/*/*/*.mo
%changelog
* Wed Jul 30 2025 UsamG1t <usamg1t@altlinux.org> 1.0-alt1
- Autotools upgrade
* Wed Jul 30 2025 UsamG1t <usamg1t@altlinux.org> 0.0-alt1
- Initial build
Соберём пакет:
@user
[user@VM sheepcounter-pkg]$ gear-hsh
<...>
+ ./configure --build=x86_64-alt-linux --host=x86_64-alt-linux --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib64 --libexecdir=/usr/lib --localstatedir=/var/lib --sharedstatedir=/var/lib --mandir=/usr/share/man --infodir=/usr/share/info --disable-dependency-tracking --disable-silent-rules --runstatedir=/var/run --without-included-gettext --disable-numbers
<...>
Отдельно заметим в выводе секцию по обработке переводов: производится автоматическая сборка
.mo-файла с его последующей установкой в правильную директорию:
Making all in po
<...>
rm -f ru.gmo && /usr/bin/msgmerge --for-msgfmt -o ru.1po ru.po sheepcounter.pot && /usr/bin/msgfmt -c --statistics --verbose -o ru.gmo ru.1po && rm -f ru.1po
<...>
Making install in po
make[1]: Entering directory '/usr/src/RPM/BUILD/sheepcounter-1.0/po'
installing ru.gmo as /usr/src/tmp/sheepcounter-buildroot/usr/share/locale/ru/LC_MESSAGES/sheepcounter.mo
<...>
Wrote: /usr/src/RPM/SRPMS/sheepcounter-1.0-alt1.src.rpm (w2.lzdio)
Wrote: /usr/src/RPM/RPMS/x86_64/sheepcounter-1.0-alt1.x86_64.rpm (w2.lzdio)
Wrote: /usr/src/RPM/RPMS/x86_64/sheepcounter-debuginfo-1.0-alt1.x86_64.rpm (w2.lzdio)
5.85user 4.55system 0:14.41elapsed 72%CPU (0avgtext+0avgdata 22040maxresident)k
128inputs+11632outputs (0major+541655minor)pagefaults 0swaps
[user@VM sheepcounter-pkg]$
Проверим работу пакета, после пересоберём его с указанием параметра и вновь проверим работу (язык в hasher из примера установлен английский по умолчанию):
@user
[user@VM ~]$ hypersh hasher/repo/SRPMS.hasher/sheepcounter-1.0-alt1.src.rpm
<...>
[user@VM ~]$ cp hasher/repo/x86_64/RPMS.hasher/sheepcounter-1.0-alt1.x86_64.rpm hasher/chroot/.in/
[user@VM ~]$ hypersh --rooter
@rooter
[root@localhost .in]# rpm -i sheepcounter-1.0-alt1.x86_64.rpm
<13>Jul 30 10:03:41 rpm: sheepcounter-1.0-alt1 1753869570 installed
[root@localhost .in]# ls /usr/share/locale/ru/LC_MESSAGES/sheepcounter.mo
/usr/share/locale/ru/LC_MESSAGES/sheepcounter.mo
[root@localhost .in]# sheepcounter
Let's count sheeps together!
How many sheeps do you want to count?
30
Oh, I know only digits, not numbers, try again:
3
We counted 1 sheep
We counted 2 sheeps
We counted 3 sheeps
[root@localhost .in]# LC_MESSAGES=ru_RU.UTF-8 sheepcounter
Давай считать овец вместе!
Сколько овец ты хочешь посчитать?
5
Мы посчитали 1 овцу
Мы посчитали 2 овцы
Мы посчитали 3 овцы
Мы посчитали 4 овцы
Мы посчитали 5 овец
[root@localhost .in]#
@builder
[builder@localhost ~]$ tree -A
.
├── RPM
│ ├── BUILD
│ ├── RPMS
│ │ └── noarch
│ ├── SOURCES
│ │ └── sheepcounter-pkg-1.0.tar.gz
│ ├── SPECS
│ │ └── sheepcounter-pkg.spec
│ └── SRPMS
├── debug
├── in
│ ├── SOURCE_DATE_EPOCH
│ ├── nosrpm
│ │ └── sheepcounter-pkg-1.0-alt1.nosrc.rpm
│ └── srpm
│ └── sheepcounter-pkg-1.0-alt1.src.rpm
└── tmp
13 directories, 5 files
[builder@localhost ~]$ rpmbuild -ba -enable=numbers RPM/SPECS/sheepcounter.spec
<...>
+ ./configure --build=x86_64-alt-linux --host=x86_64-alt-linux --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib64 --libexecdir=/usr/lib --localstatedir=/var/lib --sharedstatedir=/var/lib --mandir=/usr/share/man --infodir=/usr/share/info --disable-dependency-tracking --disable-silent-rules --runstatedir=/var/run --without-included-gettext --enable-numbers
<...>
Wrote: /usr/src/RPM/SRPMS/sheepcounter-1.0-alt1.src.rpm (w2.lzdio)
Wrote: /usr/src/RPM/RPMS/x86_64/sheepcounter-1.0-alt1.x86_64.rpm (w2.lzdio)
Wrote: /usr/src/RPM/RPMS/x86_64/sheepcounter-debuginfo-1.0-alt1.x86_64.rpm (w2.lzdio)
[builder@localhost ~]$
@rooter
[root@localhost .in]# rpm -i --replacefiles /usr/src/RPM/RPMS/x86_64/sheepcounter-1.0-alt1.x86_64.rpm
<13>Jul 30 10:10:19 rpm: sheepcounter-1.0-alt1 1753870086 installed
[root@localhost .in]#
[root@localhost .in]# sheepcounter
Let's count sheeps together!
How many sheeps do you want to count?
10
We counted 1 sheep
We counted 2 sheeps
We counted 3 sheeps
We counted 4 sheeps
We counted 5 sheeps
We counted 6 sheeps
We counted 7 sheeps
We counted 8 sheeps
We counted 9 sheeps
We counted 10 sheeps
[root@localhost .in]# LC_MESSAGES=ru_RU.UTF-8 sheepcounter
Давай считать овец вместе!
Сколько овец ты хочешь посчитать?
21
Мы посчитали 1 овцу
Мы посчитали 2 овцы
Мы посчитали 3 овцы
Мы посчитали 4 овцы
Мы посчитали 5 овец
Мы посчитали 6 овец
Мы посчитали 7 овец
Мы посчитали 8 овец
Мы посчитали 9 овец
Мы посчитали 10 овец
Мы посчитали 11 овец
Мы посчитали 12 овец
Мы посчитали 13 овец
Мы посчитали 14 овец
Мы посчитали 15 овец
Мы посчитали 16 овец
Мы посчитали 17 овец
Мы посчитали 18 овец
Мы посчитали 19 овец
Мы посчитали 20 овец
Мы посчитали 21 овцу
[root@localhost .in]#