Mercurial > molko
changeset 241:76afe639fd72
misc: add support for NLS, closes #22510 @4h
While here cleanup the path functions in sys.c/sys.h
line wrap: on
line diff
--- a/CMakeLists.txt Fri Nov 27 21:34:07 2020 +0100 +++ b/CMakeLists.txt Sat Nov 28 18:00:05 2020 +0100 @@ -24,6 +24,7 @@ set(CMAKE_C_EXTENSIONS Off) set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") +option(MOLKO_WITH_NLS "Enable native language support" On) option(MOLKO_WITH_DOC "Enable documentation (requires doxygen, doxybook2 and mkdocs)" On) option(MOLKO_WITH_TESTS "Enable unit tests" On) option(MOLKO_WITH_EXAMPLES "Enable build of examples" On) @@ -41,6 +42,7 @@ find_package(Jansson REQUIRED) find_package(SDL2 REQUIRED COMPONENTS image mixer ttf) +find_package(Intl) add_subdirectory(cmake)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmake/MolkoBuildTranslations.cmake Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,113 @@ +# +# MolkoBuildTranslations.cmake -- CMake build system for molko +# +# Copyright (c) 2020 David Demelier <markand@malikania.fr> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +if (MOLKO_WITH_NLS) + find_program(XGETTEXT_EXE xgettext) + find_program(MSGMERGE_EXE msgmerge) + find_program(MSGFMT_EXE msgfmt) +endif () + +if (MOLKO_WITH_NLS AND XGETTEXT_EXE AND MSGMERGE_EXE) + macro(molko_build_translations) + set(options) + set(oneValueArgs TARGET OUTPUTS) + set(multiValueArgs SOURCES TRANSLATIONS) + + cmake_parse_arguments(NLS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT NLS_OUTPUTS) + message(FATAL_ERROR "Missing OUTPUTS argument") + endif () + if (NOT NLS_TARGET) + message(FATAL_ERROR "Missing TARGET argument") + endif () + if (NOT NLS_SOURCES) + message(FATAL_ERROR "Missing SOURCES argument") + endif () + + # Remove non C files. + list(FILTER NLS_SOURCES INCLUDE REGEX "\\.[ch$]") + set(pot ${CMAKE_CURRENT_SOURCE_DIR}/nls/${NLS_TARGET}.pot) + + # Generate .pot file. + add_custom_target( + ${NLS_TARGET}-pot + ALL + VERBATIM + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_SOURCE_DIR}/nls + COMMAND ${XGETTEXT_EXE} -cj -k_ -kN_ -LC -s -o ${pot} ${NLS_SOURCES} + COMMENT "Generating reference translation ${pot}" + ) + set_target_properties(${NLS_TARGET}-pot PROPERTIES FOLDER translations) + + # For every translation create a msgmerge target and output file. + set(outputs) + + foreach (t ${NLS_TRANSLATIONS}) + set(po ${CMAKE_CURRENT_SOURCE_DIR}/nls/${t}.po) + set(mo ${CMAKE_CURRENT_BINARY_DIR}/${t}.mo) + + if (NOT EXISTS ${po}) + message(WARNING "Missing translation ${po}") + endif () + + add_custom_target( + ${NLS_TARGET}-po-${t} + VERBATIM + DEPENDS ${NLS_TARGET}-pot + COMMAND ${MSGMERGE_EXE} --backup=off -U ${po} ${pot} + COMMENT "Merging translation in ${po}" + ) + set_target_properties(${NLS_TARGET}-po-${t} PROPERTIES FOLDER translations) + + list(APPEND po-targets ${NLS_TARGET}-po-${t}) + + # Finally generate a .mo output from po file. + add_custom_command( + OUTPUT ${mo} + VERBATIM + COMMAND ${MSGFMT_EXE} -o ${mo} ${po} + DEPENDS ${po} + COMMENT "Generating translation binary ${mo}" + ) + + list(APPEND outputs ${mo}) + + # TODO: naming should be changed maybe. + install( + FILES ${mo} + DESTINATION ${CMAKE_INSTALL_LOCALEDIR}/${t}/LC_MESSAGES + RENAME mlk-${NLS_TARGET}.mo + ) + endforeach () + + set(${NLS_OUTPUTS} ${outputs}) + source_group("mo" FILES ${outputs}) + + add_custom_target( + ${NLS_TARGET}-po + DEPENDS ${po-targets} + COMMENT "Merging all po files" + ) + + set_target_properties(${NLS_TARGET}-po PROPERTIES FOLDER translations) + endmacro() +else () + function(molko_build_translations) + endfunction() +endif ()
--- a/cmake/MolkoDefineExecutable.cmake Fri Nov 27 21:34:07 2020 +0100 +++ b/cmake/MolkoDefineExecutable.cmake Sat Nov 28 18:00:05 2020 +0100 @@ -17,12 +17,13 @@ # include(${CMAKE_CURRENT_LIST_DIR}/MolkoBuildAssets.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/MolkoBuildTranslations.cmake) include(${CMAKE_CURRENT_LIST_DIR}/MolkoSetCompilerFlags.cmake) function(molko_define_executable) set(options) set(oneValueArgs FOLDER TARGET) - set(multiValueArgs ASSETS FLAGS INCLUDES LIBRARIES SOURCES) + set(multiValueArgs ASSETS FLAGS INCLUDES LIBRARIES SOURCES TRANSLATIONS) cmake_parse_arguments(EXE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -35,6 +36,14 @@ molko_build_assets("${EXE_ASSETS}" OUTPUTS) + if (EXE_TRANSLATIONS) + molko_build_translations( + TARGET ${EXE_TARGET} + TRANSLATIONS ${EXE_TRANSLATIONS} + SOURCES ${EXE_SOURCES} + ) + endif () + add_executable(${EXE_TARGET} ${EXE_SOURCES} ${OUTPUTS}) target_compile_definitions(${EXE_TARGET} PRIVATE ${EXE_FLAGS}) target_include_directories(
--- a/cmake/MolkoDefineLibrary.cmake Fri Nov 27 21:34:07 2020 +0100 +++ b/cmake/MolkoDefineLibrary.cmake Sat Nov 28 18:00:05 2020 +0100 @@ -67,7 +67,7 @@ function(molko_define_library) set(options EXTERNAL) set(oneValueArgs FOLDER TARGET TYPE) - set(multiValueArgs ASSETS LIBRARIES MAPS PRIVATE_FLAGS PRIVATE_INCLUDES PUBLIC_FLAGS PUBLIC_INCLUDES TILESETS SOURCES) + set(multiValueArgs ASSETS LIBRARIES MAPS PRIVATE_FLAGS PRIVATE_INCLUDES PUBLIC_FLAGS PUBLIC_INCLUDES TILESETS SOURCES TRANSLATIONS) cmake_parse_arguments(LIB "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -99,6 +99,15 @@ ${LIB_PUBLIC_INCLUDES} ) else () + if (LIB_TRANSLATIONS) + molko_build_translations( + TARGET ${LIB_TARGET} + TRANSLATIONS ${LIB_TRANSLATIONS} + SOURCES ${LIB_SOURCES} + OUTPUTS NLS_OUTPUTS + ) + endif () + add_library( ${LIB_TARGET} ${LIB_TYPE} @@ -106,7 +115,9 @@ ${ASSETS_OUTPUTS} ${MAPS_OUTPUTS} ${TILESETS_OUTPUTS} + ${NLS_OUTPUTS} ) + target_include_directories( ${LIB_TARGET} PRIVATE
--- a/examples/example-action/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-action/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -315,7 +315,7 @@ static void init(void) { - if (!core_init() || !ui_init() || !rpg_init()) + if (!core_init("fr.malikania", "actions") || !ui_init() || !rpg_init()) panic(); if (!window_open("Example - Action", W, H)) panic();
--- a/examples/example-animation/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-animation/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -53,7 +53,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "animation") || !ui_init()) panic(); if (!window_open("Example - Animation", W, H)) panic();
--- a/examples/example-audio/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-audio/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -59,7 +59,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "audio") || !ui_init()) panic(); if (!window_open("Example - Audio", W, H)) panic();
--- a/examples/example-battle/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-battle/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -146,7 +146,7 @@ static void init(void) { - if (!core_init() || !ui_init() || !rpg_init()) + if (!core_init("fr.malikania", "battle") || !ui_init() || !rpg_init()) panic(); if (!window_open("Example - Battle", W, H)) panic();
--- a/examples/example-cursor/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-cursor/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -48,7 +48,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "cursor") || !ui_init()) panic(); if (!window_open("Example - Cursor", W, H)) panic();
--- a/examples/example-debug/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-debug/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -38,7 +38,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "debug") || !ui_init()) panic(); if (!window_open("Example - Debug", W, H)) panic();
--- a/examples/example-drawable/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-drawable/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -71,7 +71,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "drawable") || !ui_init()) panic(); if (!window_open("Example - Drawable", W, H)) panic();
--- a/examples/example-font/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-font/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -52,7 +52,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "font") || !ui_init()) panic(); if (!window_open("Example - Font", W, H)) panic();
--- a/examples/example-gridmenu/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-gridmenu/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -39,7 +39,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "grid-menu") || !ui_init()) panic(); if (!window_open("Example - Grid menu", W, H)) panic();
--- a/examples/example-label/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-label/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -102,7 +102,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "label") || !ui_init()) panic(); if (!window_open("Example - Label", W, H)) panic();
--- a/examples/example-map/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-map/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -272,7 +272,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "map") || !ui_init()) panic(); if (!window_open("Example - Map", W, H)) panic();
--- a/examples/example-message/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-message/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -44,7 +44,7 @@ static void init(void) { - if (!core_init() || !ui_init() || !rpg_init()) + if (!core_init("fr.malikania", "message") || !ui_init() || !rpg_init()) panic(); if (!window_open("Example - Message", W, H)) panic();
--- a/examples/example-sprite/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-sprite/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -63,7 +63,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "sprite") || !ui_init()) panic(); if (!window_open("Example - Sprite", W, H)) panic();
--- a/examples/example-trace/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-trace/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -38,7 +38,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "trace") || !ui_init()) panic(); if (!window_open("Example - Trace", W, H)) panic();
--- a/examples/example-ui/main.c Fri Nov 27 21:34:07 2020 +0100 +++ b/examples/example-ui/main.c Sat Nov 28 18:00:05 2020 +0100 @@ -129,7 +129,7 @@ static void init(void) { - if (!core_init() || !ui_init()) + if (!core_init("fr.malikania", "ui") || !ui_init()) panic(); if (!window_open("Example - UI", W, H)) panic();
--- a/libadventure/adventure/molko.c Fri Nov 27 21:34:07 2020 +0100 +++ b/libadventure/adventure/molko.c Sat Nov 28 18:00:05 2020 +0100 @@ -80,7 +80,7 @@ void molko_init(void) { - if (!core_init() || !ui_init() || !rpg_init()) + if (!core_init("fr.malikania", "molko") || !ui_init() || !rpg_init()) panic(); if (!window_open("Molko's Adventure", WINDOW_WIDTH, WINDOW_HEIGHT)) panic();
--- a/libcore/CMakeLists.txt Fri Nov 27 21:34:07 2020 +0100 +++ b/libcore/CMakeLists.txt Sat Nov 28 18:00:05 2020 +0100 @@ -29,6 +29,11 @@ ) set( + PO + ${libcore_SOURCE_DIR}/nls/fr.po +) + +set( SOURCES ${libcore_SOURCE_DIR}/core/action.c ${libcore_SOURCE_DIR}/core/action.h @@ -41,6 +46,7 @@ ${libcore_SOURCE_DIR}/core/color.h ${libcore_SOURCE_DIR}/core/core.c ${libcore_SOURCE_DIR}/core/core.h + ${libcore_SOURCE_DIR}/core/core_p.h ${libcore_SOURCE_DIR}/core/drawable.c ${libcore_SOURCE_DIR}/core/drawable.h ${libcore_SOURCE_DIR}/core/error.c @@ -76,11 +82,14 @@ ${libcore_SOURCE_DIR}/core/state.h ${libcore_SOURCE_DIR}/core/sys.c ${libcore_SOURCE_DIR}/core/sys.h + ${libcore_SOURCE_DIR}/core/sysconfig.h.in ${libcore_SOURCE_DIR}/core/texture.c ${libcore_SOURCE_DIR}/core/texture.h ${libcore_SOURCE_DIR}/core/texture_p.h ${libcore_SOURCE_DIR}/core/trace.c ${libcore_SOURCE_DIR}/core/trace.h + ${libcore_SOURCE_DIR}/core/translate.c + ${libcore_SOURCE_DIR}/core/translate.h ${libcore_SOURCE_DIR}/core/util.c ${libcore_SOURCE_DIR}/core/util.h ${libcore_SOURCE_DIR}/core/wait.c @@ -90,13 +99,25 @@ ${libcore_SOURCE_DIR}/core/window_p.h ) +configure_file( + ${libcore_SOURCE_DIR}/core/sysconfig.h.in + ${libcore_BINARY_DIR}/sysconfig.h +) + check_library_exists(m sqrt "" LIBM) +if (MOLKO_WITH_NLS AND Intl_FOUND) + list(APPEND LIBS ${Intl_LIBRARIES}) + list(APPEND INCS ${Intl_INCLUDE_DIRS}) +endif () + molko_define_library( TARGET libcore - SOURCES ${SOURCES} ${SQL_ASSETS} + SOURCES ${SOURCES} ${SQL_ASSETS} ${PO} ASSETS ${SQL_ASSETS} + TRANSLATIONS fr LIBRARIES + ${LIBS} $<$<BOOL:${LIBM}>:m> libsqlite SDL2::SDL2 @@ -110,8 +131,11 @@ PUBLIC_FLAGS _XOPEN_SOURCE=700 PUBLIC_INCLUDES + ${INCS} $<BUILD_INTERFACE:${libcore_SOURCE_DIR}> + $<BUILD_INTERFACE:${libcore_BINARY_DIR}> ) +source_group(assets/sql FILES ${SQL_ASSETS}) source_group(core FILES ${SOURCES}) -source_group(core/assets/sql FILES ${SQL_ASSETS}) +source_group(nls FILES ${PO})
--- a/libcore/core/core.c Fri Nov 27 21:34:07 2020 +0100 +++ b/libcore/core/core.c Sat Nov 28 18:00:05 2020 +0100 @@ -1,5 +1,5 @@ /* - * core.c -- libcore convenient header + * core.c -- libcore main entry * * Copyright (c) 2020 David Demelier <markand@malikania.fr> * @@ -16,19 +16,29 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <assert.h> #include <stddef.h> #include <stdlib.h> #include <time.h> #include "core.h" #include "sys.h" +#include "translate.h" bool -core_init(void) +core_init(const char *organization, const char *name) { + assert(organization); + assert(name); + srand(time(NULL)); - return sys_init(); + if (!sys_init(organization, name)) + return false; + + translate_init("mlk-libcore"); + + return true; } void
--- a/libcore/core/core.h Fri Nov 27 21:34:07 2020 +0100 +++ b/libcore/core/core.h Sat Nov 28 18:00:05 2020 +0100 @@ -1,5 +1,5 @@ /* - * core.h -- libcore convenient header + * core.c -- libcore main entry * * Copyright (c) 2020 David Demelier <markand@malikania.fr> * @@ -21,7 +21,7 @@ /** * \file core.h - * \brief libcore convenient header. + *\brief libcore convenient header. */ #include <stdbool.h> @@ -29,10 +29,14 @@ /** * Initialize the core library. * + * \pre organization != NULL + * \pre name != NULL + * \param organization the name of the organization + * \param name the game name * \return False on errors. */ bool -core_init(void); +core_init(const char *organization, const char *name); /** * Close the core library.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcore/core/core_p.h Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,31 @@ +/* + * core_p -- libcore private definitions + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_CORE_CORE_P_H +#define MOLKO_CORE_CORE_P_H + +#include "sysconfig.h" + +#if defined(MOLKO_WITH_NLS) +# include <libintl.h> +# define _(s) dgettext("mlk-libcore", s) +#else +# define _(s) +#endif + +#endif /* !MOLKO_CORE_CORE_P_H */
--- a/libcore/core/panic.c Fri Nov 27 21:34:07 2020 +0100 +++ b/libcore/core/panic.c Sat Nov 28 18:00:05 2020 +0100 @@ -20,13 +20,14 @@ #include <stdio.h> #include <stdlib.h> +#include "core_p.h" #include "error.h" #include "panic.h" static void terminate(void) { - fprintf(stderr, "abort: %s\n", error()); + fprintf(stderr, _("abort: %s\n"), error()); abort(); exit(1); } @@ -72,6 +73,6 @@ * This should not happen, if it does it means the user did not fully * satisfied the constraint of panic_handler. */ - fprintf(stderr, "abort: panic handler returned"); + fprintf(stderr, _("abort: panic handler returned\n")); exit(1); }
--- a/libcore/core/save.c Fri Nov 27 21:34:07 2020 +0100 +++ b/libcore/core/save.c Sat Nov 28 18:00:05 2020 +0100 @@ -28,6 +28,7 @@ #include <core/assets/sql/property-remove.h> #include <core/assets/sql/property-set.h> +#include "core_p.h" #include "error.h" #include "save.h" #include "sys.h" @@ -46,6 +47,12 @@ return true; } +static const char * +path(unsigned int idx) +{ + return pprintf("%s/%u", sys_dir(SYS_DIR_SAVE), idx); +} + static bool execu(struct save *db, const unsigned char *sql) { @@ -57,7 +64,7 @@ { assert(db); - return save_open_path(db, sys_savepath(idx), mode); + return save_open_path(db, path(idx), mode); } bool @@ -75,7 +82,7 @@ for (size_t i = 0; i < NELEM(table); ++i) { if (!save_get_property(db, &table[i].prop)) { sqlite3_close(db->handle); - return errorf("database not initialized correctly"); + return errorf(_("database not initialized correctly")); } *table[i].date = strtoull(table[i].prop.value, NULL, 10); @@ -165,7 +172,7 @@ switch (sqlite3_step(stmt)) { case SQLITE_DONE: /* Not found. */ - ret = errorf("property '%s' was not found", prop->key); + ret = errorf(_("property '%s' was not found"), prop->key); break; case SQLITE_ROW: /* Found. */
--- a/libcore/core/sys.c Fri Nov 27 21:34:07 2020 +0100 +++ b/libcore/core/sys.c Sat Nov 28 18:00:05 2020 +0100 @@ -16,89 +16,76 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "sysconfig.h" + #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> +#if defined(_WIN32) +# include <shlwapi.h> +#endif + #include <SDL.h> #include <SDL_image.h> #include <SDL_mixer.h> #include <SDL_ttf.h> -#if !defined(_WIN32) /* Assuming POSIX */ -# include <sys/types.h> -# include <dirent.h> -#endif - #include "error.h" #include "sound.h" #include "sys.h" -#if defined(_WIN32) - -static void -determine(char path[], size_t pathlen) -{ - char *base = SDL_GetBasePath(); +static struct { + char organization[128]; + char name[128]; +} info = { + .organization = "fr.malikania", + .name = "molko" +}; - /* On Windows, the data hierarchy is the same as the project. */ - snprintf(path, pathlen, "%sassets", base); - SDL_free(base); -} +static const char *paths[] = { + [SYS_DIR_BIN] = MOLKO_BINDIR, + [SYS_DIR_DATA] = MOLKO_DATADIR, + [SYS_DIR_LOCALE] = MOLKO_LOCALEDIR +}; -#else /* Assuming POSIX */ +static const char *abspaths[] = { + [SYS_DIR_BIN] = MOLKO_ABS_BINDIR, + [SYS_DIR_DATA] = MOLKO_ABS_DATADIR, + [SYS_DIR_LOCALE] = MOLKO_ABS_LOCALEDIR +}; + +#if defined(_WIN32) static bool is_absolute(const char *path) { - assert(path); - - return path[0] == '/'; + return !PathIsRelativeA(path); } -static void -determine(char path[], size_t pathlen) -{ - char localassets[PATH_MAX]; - char *base = SDL_GetBasePath(); - DIR *dp; - - /* Try assets directory where executable lives. */ - snprintf(localassets, sizeof (localassets), "%sassets", base); +#else - if ((dp = opendir(localassets))) { - snprintf(path, pathlen, "%sassets", base); - closedir(dp); - } else { - /* We are not in the project source directory. */ - if (is_absolute(SHAREDIR)) { - /* SHAREDIR is absolute */ - snprintf(path, pathlen, "%s/molko", SHAREDIR); - } else if (is_absolute(BINDIR)) { - /* SHAREDIR is relative but BINDIR is absolute */ - snprintf(path, pathlen, "%s/%s/molko", PREFIX, SHAREDIR); - } else { - /* SHAREDIR, BINDIR are both relative */ - char *ptr = strstr(base, BINDIR); - - if (ptr) { - *ptr = '\0'; - snprintf(path, pathlen, "%s%s/molko", base, SHAREDIR); - } else { - /* Unable to determine. */ - snprintf(path, pathlen, "."); - } - } - } - - SDL_free(base); +static bool +is_absolute(const char *path) +{ + return path[0] == '/'; } #endif +static char * +normalize(char *str) +{ + for (char *p = str; *p; ++p) + if (*p == '\\') + *p = '/'; + + return str; +} + bool -sys_init(void) +sys_init(const char *organization, const char *name) { #if defined(__MINGW64__) /* On MinGW buffering leads to painful debugging. */ @@ -106,6 +93,9 @@ setbuf(stdout, NULL); #endif + snprintf(info.organization, sizeof (info.organization), "%s", organization); + snprintf(info.name, sizeof (info.name), "%s", name); + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) return errorf("%s", SDL_GetError()); if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) @@ -122,55 +112,97 @@ return true; } -const char * -sys_datadir(void) +static const char * +absolute(const char *which) { static char path[PATH_MAX]; - if (path[0] == '\0') - determine(path, sizeof (path)); + snprintf(path, sizeof (path), "%s", which); - return path; + return normalize(path); } -const char * -sys_datapath(const char *fmt, ...) +static const char * +system_directory(enum sys_dir kind) { - const char *ret; - va_list ap; + static char path[PATH_MAX]; + static char ret[PATH_MAX]; + char *base, *binsect; + + /* 1. Get current binary directory. */ + base = SDL_GetBasePath(); + + /* + * 2. Decompose the path to the given special directory by computing + * relative directory to it from where the binary is located. + * + * Example: + * PREFIX/bin/mlk + * PREFIX/share/molko + * + * The path to the data is ../share/molko starting from the binary. + * + * If path to binary is absolute we can't determine relative paths to + * any other directory and use the absolute one instead. + * + * Also, on some platforms SDL_GetBasePath isn't implemented and returns + * NULL, in that case return the fallback to the installation prefix. + */ + if (is_absolute(paths[SYS_DIR_BIN]) || is_absolute(paths[kind]) || !base) + return absolute(abspaths[kind]); - va_start(ap, fmt); - ret = sys_datapathv(fmt, ap); - va_end(ap); + /* + * 3. Put the base path into the path and remove the value of + * MOLKO_BINDIR. + * + * Example: + * from: /usr/local/bin + * to: /usr/local + */ + snprintf(path, sizeof (path), "%s", base); + SDL_free(base); + + if ((binsect = strstr(path, paths[SYS_DIR_BIN]))) + *binsect = '\0'; + + /* 4. For data directories, we append the program name. */ + if (kind == SYS_DIR_DATA) + snprintf(ret, sizeof (ret), "%s%s/%s", path, paths[kind], info.name); + else + snprintf(ret, sizeof (ret), "%s%s", path, paths[kind]); - return ret; + return normalize(ret); +} + +static const char * +user_directory(enum sys_dir kind) +{ + /* Kept for future use. */ + (void)kind; + + static char path[PATH_MAX]; + char *pref; + + if ((pref = SDL_GetPrefPath(info.organization, info.name))) { + snprintf(path, sizeof (path), "%s", pref); + SDL_free(pref); + } else + snprintf(path, sizeof (path), "./"); + + return NULL; } const char * -sys_datapathv(const char *fmt, va_list ap) +sys_dir(enum sys_dir kind) { - static char path[PATH_MAX]; - char filename[FILENAME_MAX]; - - vsnprintf(filename, sizeof (filename), fmt, ap); - snprintf(path, sizeof (path), "%s/%s", sys_datadir(), filename); - - return path; -} - -const char * -sys_savepath(unsigned int idx) -{ - static char path[PATH_MAX]; - char *pref; - - if ((pref = SDL_GetPrefPath("malikania", "molko"))) { - snprintf(path, sizeof (path), "%ssave-%u", pref, idx); - SDL_free(pref); - } else - snprintf(path, sizeof (path), "save-%u", idx); - - return path; + switch (kind) { + case SYS_DIR_BIN: + case SYS_DIR_DATA: + case SYS_DIR_LOCALE: + return system_directory(kind); + default: + return user_directory(kind); + } } void
--- a/libcore/core/sys.h Fri Nov 27 21:34:07 2020 +0100 +++ b/libcore/core/sys.h Sat Nov 28 18:00:05 2020 +0100 @@ -29,55 +29,39 @@ #include <stdbool.h> /** + * \brief Kind of special directories. + */ +enum sys_dir { + SYS_DIR_BIN, /*!< Path to binaries. */ + SYS_DIR_DATA, /*!< Directory containing data. */ + SYS_DIR_LOCALE, /*!< Path to NLS catalogs. */ + SYS_DIR_SAVE, /*!< User directory for save databases. */ +}; + +/** * Initialize the system. * * This function is automatically called from \ref core_init and thus not * necessary from user. * + * \pre organization != NULL + * \pre name != NULL + * \param organization the name of the organization + * \param name the game name * \return False on error. */ bool -sys_init(void); - -/** - * Get the base system directory path. - * - * \return the path where the executable lives - */ -const char * -sys_datadir(void); - -/** - * Construct path to assets directory using printf-like format. - * - * \param fmt the format string - * \return the path to the file - * \note This function returns pointer to static string. - */ -const char * -sys_datapath(const char *fmt, ...); +sys_init(const char *organization, const char *name); /** - * Similar to \a sys_datapath. + * Get a system or user directory preferred for this platform. * - * \param fmt the format string - * \param ap the variadic arguments pointer - * \return the path to the file - * \note This function returns pointer to static string. + * \pre kind must be valid + * \param kind kind of special directory + * \return A non-NULL pointer to a static storage path. */ const char * -sys_datapathv(const char *fmt, va_list ap); - -/** - * Compute the path to the save file for the given game state. - * - * \param idx the save number - * \return the path to the database file - * \note This only compute the path, it does not check the presence of the file - * \post The returned value will never be NULL - */ -const char * -sys_savepath(unsigned int idx); +sys_dir(enum sys_dir kind); /** * Close the system.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcore/core/sysconfig.h.in Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,32 @@ +/* + * sysconfig.h -- build time configuration + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_CORE_SYSCONFIG_H +#define MOLKO_CORE_SYSCONFIG_H + +#cmakedefine MOLKO_WITH_NLS + +#define MOLKO_BINDIR "@CMAKE_INSTALL_BINDIR@" +#define MOLKO_DATADIR "@CMAKE_INSTALL_DATADIR@" +#define MOLKO_LOCALEDIR "@CMAKE_INSTALL_LOCALEDIR@" + +#define MOLKO_ABS_BINDIR "@CMAKE_INSTALL_FULL_BINDIR" +#define MOLKO_ABS_DATADIR "@CMAKE_INSTALL_FULL_DATADIR" +#define MOLKO_ABS_LOCALEDIR "@CMAKE_INSTALL_FULL_LOCALEDIR" + +#endif /* !MOLKO_CORE_SYSCONFIG_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcore/core/translate.c Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,44 @@ +/* + * translate.c -- native language support + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "sysconfig.h" + +#if defined(MOLKO_WITH_NLS) +# include <libintl.h> +#endif + +#include "sys.h" +#include "translate.h" +#include "util.h" + +#include <stdio.h> + +bool +translate_init(const char *name) +{ +#if defined(MOLKO_WITH_NLS) + if (!bindtextdomain(name, sys_dir(SYS_DIR_LOCALE))) + return false; +#endif + return true; +} + +void +translate_finish(void) +{ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcore/core/translate.h Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,40 @@ +/* + * translate.h -- native language support + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_CORE_TRANSLATE_H +#define MOLKO_CORE_TRANSLATE_H + +#include <stdbool.h> + +/** + * Initialize native language support. + * + * \pre name != NULL + * \param name the domain name to initialize (e.g mlk-libcore) + * \return True if correctly initialized. + */ +bool +translate_init(const char *name); + +/** + * Close the native language support. + */ +void +translate_finish(void); + +#endif /* !MOLKO_CORE_TRANSLATE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcore/nls/fr.po Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,37 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-28 16:45+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: /Users/markand/Dev/molko/libcore/core/panic.c:30 +#, c-format +msgid "abort: %s\n" +msgstr "fatal: %s\n" + +#: /Users/markand/Dev/molko/libcore/core/panic.c:76 +#, c-format +msgid "abort: panic handler returned\n" +msgstr "fatal: la fonction de panique n'aurait pas du continuer\n" + +#: /Users/markand/Dev/molko/libcore/core/save.c:85 +msgid "database not initialized correctly" +msgstr "database non initialisée" + +#: /Users/markand/Dev/molko/libcore/core/save.c:175 +#, c-format +msgid "property '%s' was not found" +msgstr "propriété '%s' non trouvée"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcore/nls/libcore.pot Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,37 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-28 17:53+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: /Users/markand/Dev/molko/libcore/core/panic.c:30 +#, c-format +msgid "abort: %s\n" +msgstr "" + +#: /Users/markand/Dev/molko/libcore/core/panic.c:76 +#, c-format +msgid "abort: panic handler returned\n" +msgstr "" + +#: /Users/markand/Dev/molko/libcore/core/save.c:85 +msgid "database not initialized correctly" +msgstr "" + +#: /Users/markand/Dev/molko/libcore/core/save.c:175 +#, c-format +msgid "property '%s' was not found" +msgstr ""
--- a/librpg/CMakeLists.txt Fri Nov 27 21:34:07 2020 +0100 +++ b/librpg/CMakeLists.txt Sat Nov 28 18:00:05 2020 +0100 @@ -74,6 +74,7 @@ ${librpg_SOURCE_DIR}/rpg/message.h ${librpg_SOURCE_DIR}/rpg/rpg.c ${librpg_SOURCE_DIR}/rpg/rpg.h + ${librpg_SOURCE_DIR}/rpg/rpg_p.h ${librpg_SOURCE_DIR}/rpg/selection.h ${librpg_SOURCE_DIR}/rpg/spell.c ${librpg_SOURCE_DIR}/rpg/spell.h @@ -87,9 +88,15 @@ ${librpg_SOURCE_DIR}/rpg/walksprite.h ) +set( + PO + ${librpg_SOURCE_DIR}/nls/fr.po +) + molko_define_library( TARGET librpg - SOURCES ${SOURCES} + TRANSLATIONS fr + SOURCES ${SOURCES} ${PO} LIBRARIES libcore libui @@ -98,4 +105,4 @@ ) source_group(rpg FILES ${SOURCES}) - +source_group(nls FILES ${PO})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/nls/fr.po Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,134 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-28 17:41+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-bar.c:127 +msgid "Attack" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-bar.c:134 +msgid "Magic" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-bar.c:141 +msgid "Objects" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-bar.c:148 +msgid "Special" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-state-victory.c:88 +msgid "Victory!" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-state-lost.c:87 +msgid "You have been defeated..." +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:241 +msgid "could not parse image" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:130 +msgid "could not parse tileset" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:92 +#, c-format +msgid "ignoring action %d,%d,%u,%u,%s" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:61 +#, c-format +msgid "invalid layer type: %s" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:175 +msgid "invalid origin" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/message.c:277 +msgid "message has null dimensions" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/message.c:140 +#, c-format +msgid "message height too small: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/message.c:171 +msgid "message is automatic but has zero timeout" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/message.c:138 +#, c-format +msgid "message width too small: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:236 +msgid "missing background layer" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:238 +msgid "missing foreground layer" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:114 +msgid "missing layer type definition" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:110 +msgid "missing map dimensions before layer" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:239 +msgid "missing tile dimensions before image" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:240 +msgid "missing tileset" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:298 +msgid "missing tileset image" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:229 +msgid "missing title" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:157 +msgid "null map columns" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:166 +msgid "null map rows" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:146 +msgid "null map title" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:142 +msgid "tileheight is null" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:133 +msgid "tilewidth is null" +msgstr ""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/nls/librpg.pot Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,134 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-28 17:51+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-bar.c:127 +msgid "Attack" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-bar.c:134 +msgid "Magic" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-bar.c:141 +msgid "Objects" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-bar.c:148 +msgid "Special" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-state-victory.c:88 +msgid "Victory!" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/battle-state-lost.c:87 +msgid "You have been defeated..." +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:241 +msgid "could not parse image" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:130 +msgid "could not parse tileset" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:92 +#, c-format +msgid "ignoring action %d,%d,%u,%u,%s" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:61 +#, c-format +msgid "invalid layer type: %s" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:175 +msgid "invalid origin" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/message.c:277 +msgid "message has null dimensions" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/message.c:140 +#, c-format +msgid "message height too small: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/message.c:171 +msgid "message is automatic but has zero timeout" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/message.c:138 +#, c-format +msgid "message width too small: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:236 +msgid "missing background layer" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:238 +msgid "missing foreground layer" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:114 +msgid "missing layer type definition" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:110 +msgid "missing map dimensions before layer" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:239 +msgid "missing tile dimensions before image" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:240 +msgid "missing tileset" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:298 +msgid "missing tileset image" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:229 +msgid "missing title" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:157 +msgid "null map columns" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:166 +msgid "null map rows" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/map-file.c:146 +msgid "null map title" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:142 +msgid "tileheight is null" +msgstr "" + +#: /Users/markand/Dev/molko/librpg/rpg/tileset-file.c:133 +msgid "tilewidth is null" +msgstr ""
--- a/librpg/rpg/battle-bar.c Fri Nov 27 21:34:07 2020 +0100 +++ b/librpg/rpg/battle-bar.c Sat Nov 28 18:00:05 2020 +0100 @@ -32,6 +32,7 @@ #include "battle-bar.h" #include "character.h" #include "spell.h" +#include "rpg_p.h" static void draw_status_character_stats(const struct battle *bt, @@ -115,7 +116,7 @@ static void draw_menu(const struct battle_bar *bar, const struct battle *bt) { - static struct { + struct { unsigned int w, h; enum align align; struct label label; @@ -123,28 +124,28 @@ { .align = ALIGN_TOP, .label = { - .text = "Attack", + .text = _("Attack"), .flags = LABEL_FLAGS_SHADOW } }, { .align = ALIGN_RIGHT, .label = { - .text = "Magic", + .text = _("Magic"), .flags = LABEL_FLAGS_SHADOW } }, { .align = ALIGN_BOTTOM, .label = { - .text = "Objects", + .text = _("Objects"), .flags = LABEL_FLAGS_SHADOW } }, { .align = ALIGN_LEFT, .label = { - .text = "Special", + .text = _("Special"), .flags = LABEL_FLAGS_SHADOW } }
--- a/librpg/rpg/battle-state-lost.c Fri Nov 27 21:34:07 2020 +0100 +++ b/librpg/rpg/battle-state-lost.c Sat Nov 28 18:00:05 2020 +0100 @@ -29,6 +29,7 @@ #include "battle-state.h" #include "battle-state-closing.h" #include "battle-state-victory.h" +#include "rpg_p.h" struct lost { struct battle_state self; @@ -83,7 +84,7 @@ lost->self.update = update; lost->self.draw = draw; - lost->msg.text[0] = "You have been defeated..."; + lost->msg.text[0] = _("You have been defeated..."); lost->msg.theme = bt->theme; lost->msg.flags = MESSAGE_FLAGS_AUTOMATIC | MESSAGE_FLAGS_FADEIN |
--- a/librpg/rpg/battle-state-victory.c Fri Nov 27 21:34:07 2020 +0100 +++ b/librpg/rpg/battle-state-victory.c Sat Nov 28 18:00:05 2020 +0100 @@ -29,6 +29,7 @@ #include "battle-state.h" #include "battle-state-closing.h" #include "battle-state-victory.h" +#include "rpg_p.h" struct victory { struct battle_state self; @@ -84,7 +85,7 @@ vic->self.update = update; vic->self.draw = draw; - vic->msg.text[0] = "Victory!"; + vic->msg.text[0] = _("Victory!"); vic->msg.theme = bt->theme; vic->msg.flags = MESSAGE_FLAGS_AUTOMATIC | MESSAGE_FLAGS_FADEIN |
--- a/librpg/rpg/map-file.c Fri Nov 27 21:34:07 2020 +0100 +++ b/librpg/rpg/map-file.c Sat Nov 28 18:00:05 2020 +0100 @@ -32,6 +32,7 @@ #include <core/trace.h> #include "map-file.h" +#include "rpg_p.h" /* Create %<v>c string literal for scanf */ #define MAX_F(v) MAX_F_(v) @@ -57,7 +58,7 @@ else if (strcmp(layer_name, "above") == 0) layer_type = MAP_LAYER_TYPE_ABOVE; else - return errorf("invalid layer type: %s", layer_name); + return errorf(_("invalid layer type: %s"), layer_name); amount = ctx->map->columns * ctx->map->rows; current = 0; @@ -88,7 +89,7 @@ struct action *act; if (!ctx->mf->load_action) { - tracef("ignoring action %d,%d,%u,%u,%s", x, y, w, h, exec); + tracef(_("ignoring action %d,%d,%u,%u,%s"), x, y, w, h, exec); continue; } @@ -106,11 +107,11 @@ /* Check if weight/height has been specified. */ if (ctx->map->columns == 0 || ctx->map->rows == 0) - return errorf("missing map dimensions before layer"); + return errorf(_("missing map dimensions before layer")); /* Determine layer type. */ if (sscanf(line, "layer|%32s", layer_name) <= 0) - return errorf("missing layer type definition"); + return errorf(_("missing layer type definition")); if (strcmp(layer_name, "actions") == 0) return parse_actions(ctx); @@ -126,7 +127,7 @@ struct tileset_file *tf = &mf->tileset_file; if (!(p = strchr(line, '|'))) - return errorf("could not parse tileset"); + return errorf(_("could not parse tileset")); snprintf(path, sizeof (path), "%s/%s", ctx->basedir, p + 1); @@ -142,7 +143,7 @@ parse_title(struct context *ctx, const char *line) { if (sscanf(line, "title|" MAX_F(MAP_FILE_TITLE_MAX), ctx->mf->title) != 1 || strlen(ctx->mf->title) == 0) - return errorf("null map title"); + return errorf(_("null map title")); ctx->map->title = ctx->mf->title; @@ -153,7 +154,7 @@ parse_columns(struct context *ctx, const char *line) { if (sscanf(line, "columns|%u", &ctx->map->columns) != 1 || ctx->map->columns == 0) - return errorf("null map columns"); + return errorf(_("null map columns")); return true; } @@ -162,7 +163,7 @@ parse_rows(struct context *ctx, const char *line) { if (sscanf(line, "rows|%u", &ctx->map->rows) != 1 || ctx->map->rows == 0) - return errorf("null map rows"); + return errorf(_("null map rows")); return true; } @@ -171,7 +172,7 @@ parse_origin(struct context *ctx, const char *line) { if (sscanf(line, "origin|%d|%d", &ctx->map->player_x, &ctx->map->player_y) != 2) - return errorf("invalid origin"); + return errorf(_("invalid origin")); return true; } @@ -225,18 +226,18 @@ * Check that we have parsed every required components. */ if (!map->title) - return errorf("missing title"); + return errorf(_("missing title")); /* * We don't need to check width/height because parsing layers and * tilesets already check for their presence, so only check layers. */ if (!map->layers[0].tiles) - return errorf("missing background layer"); + return errorf(_("missing background layer")); if (!map->layers[1].tiles) - return errorf("missing foreground layer"); + return errorf(_("missing foreground layer")); if (!tileset_ok(map->tileset)) - return errorf("missing tileset"); + return errorf(_("missing tileset")); return true; }
--- a/librpg/rpg/message.c Fri Nov 27 21:34:07 2020 +0100 +++ b/librpg/rpg/message.c Sat Nov 28 18:00:05 2020 +0100 @@ -36,6 +36,7 @@ #include <ui/theme.h> #include "message.h" +#include "rpg_p.h" #define THEME(msg) (msg->theme ? msg->theme : theme_default()) @@ -134,9 +135,9 @@ label.flags = LABEL_FLAGS_SHADOW; if (label.x + lw > msg->w) - tracef("message width too small: %u < %u", msg->w, min_width(msg)); + tracef(_("message width too small: %u < %u"), msg->w, min_width(msg)); if (label.y + lh > msg->h) - tracef("message height too small: %u < %u", msg->h, min_height(msg)); + tracef(_("message height too small: %u < %u"), msg->h, min_height(msg)); /* * The function label_draw will use THEME_COLOR_NORMAL to draw @@ -167,7 +168,7 @@ : MESSAGE_STATE_SHOWING; if (msg->flags & MESSAGE_FLAGS_AUTOMATIC && msg->timeout == 0) - tracef("message is automatic but has zero timeout"); + tracef(_("message is automatic but has zero timeout")); } void @@ -273,7 +274,7 @@ unsigned int w, h; if (msg->w == 0 || msg->h == 0) { - tracef("message has null dimensions"); + tracef(_("message has null dimensions")); return; }
--- a/librpg/rpg/rpg.c Fri Nov 27 21:34:07 2020 +0100 +++ b/librpg/rpg/rpg.c Sat Nov 28 18:00:05 2020 +0100 @@ -16,18 +16,21 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <core/translate.h> + #include "rpg.h" +#include "rpg_p.h" bool rpg_init(void) { - /* Currently empty, placeholder for future. */ +#if defined(MOLKO_WITH_NLS) + translate_init("mlk-librpg"); +#endif + return true; } -/** - * Close the rpg library. - */ void rpg_finish(void) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/librpg/rpg/rpg_p.h Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,31 @@ +/* + * rpg_p -- librpg private definitions + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_RPG_RPG_P_H +#define MOLKO_RPG_RPG_P_H + +#include "sysconfig.h" + +#if defined(MOLKO_WITH_NLS) +# include <libintl.h> +# define _(s) dgettext("mlk-librpg", s) +#else +# define _(s) +#endif + +#endif /* !MOLKO_RPG_RPG_P_H */
--- a/librpg/rpg/tileset-file.c Fri Nov 27 21:34:07 2020 +0100 +++ b/librpg/rpg/tileset-file.c Sat Nov 28 18:00:05 2020 +0100 @@ -32,6 +32,7 @@ #include <core/image.h> #include <core/util.h> +#include "rpg_p.h" #include "tileset-file.h" #include "tileset.h" @@ -129,7 +130,7 @@ parse_tilewidth(struct context *ctx, const char *line) { if (sscanf(line, "tilewidth|%u", &ctx->tilewidth) != 1 || ctx->tilewidth == 0) - return errorf("tilewidth is null"); + return errorf(_("tilewidth is null")); return true; } @@ -138,7 +139,7 @@ parse_tileheight(struct context *ctx, const char *line) { if (sscanf(line, "tileheight|%u", &ctx->tileheight) != 1 || ctx->tileheight == 0) - return errorf("tileheight is null"); + return errorf(_("tileheight is null")); return true; } @@ -235,9 +236,9 @@ char *p; if (ctx->tilewidth == 0 || ctx->tileheight == 0) - return errorf("missing tile dimensions before image"); + return errorf(_("missing tile dimensions before image")); if (!(p = strchr(line, '|'))) - return errorf("could not parse image"); + return errorf(_("could not parse image")); if (!image_open(&ctx->tf->image, pprintf("%s/%s", ctx->basedir, p + 1))) return false; @@ -294,7 +295,7 @@ check(const struct tileset *tileset) { if (!tileset->sprite) - return errorf("missing tileset image"); + return errorf(_("missing tileset image")); return true; }
--- a/libui/CMakeLists.txt Fri Nov 27 21:34:07 2020 +0100 +++ b/libui/CMakeLists.txt Sat Nov 28 18:00:05 2020 +0100 @@ -25,6 +25,11 @@ ) set( + PO + ${libui_SOURCE_DIR}/nls/fr.po +) + +set( SOURCES ${libui_SOURCE_DIR}/ui/align.c ${libui_SOURCE_DIR}/ui/align.h @@ -44,11 +49,13 @@ ${libui_SOURCE_DIR}/ui/theme.h ${libui_SOURCE_DIR}/ui/ui.c ${libui_SOURCE_DIR}/ui/ui.h + ${libui_SOURCE_DIR}/ui/ui_p.h ) molko_define_library( TARGET libui - SOURCES ${SOURCES} + TRANSLATIONS fr + SOURCES ${SOURCES} ${PO} ${ASSETS} ASSETS ${ASSETS} LIBRARIES libcore @@ -56,4 +63,6 @@ $<BUILD_INTERFACE:${libui_SOURCE_DIR}> ) +source_group(TREE ${libui_SOURCE_DIR}/ui/assets PREFIX assets FILES ${ASSETS}) source_group(ui FILES ${SOURCES}) +source_group(nls FILES ${PO})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/nls/fr.po Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,38 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-28 17:33+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: /Users/markand/Dev/molko/libui/ui/button.c:75 +#, c-format +msgid "button height is too small for text: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/libui/ui/button.c:73 +#, c-format +msgid "button width is too small for text: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/libui/ui/gridmenu.c:86 +#, c-format +msgid "gridmenu height is too small: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/libui/ui/gridmenu.c:78 +#, c-format +msgid "gridmenu width is too small: %u < %u" +msgstr ""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/nls/libui.pot Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,38 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-28 17:50+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: /Users/markand/Dev/molko/libui/ui/button.c:75 +#, c-format +msgid "button height is too small for text: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/libui/ui/button.c:73 +#, c-format +msgid "button width is too small for text: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/libui/ui/gridmenu.c:86 +#, c-format +msgid "gridmenu height is too small: %u < %u" +msgstr "" + +#: /Users/markand/Dev/molko/libui/ui/gridmenu.c:78 +#, c-format +msgid "gridmenu width is too small: %u < %u" +msgstr ""
--- a/libui/ui/button.c Fri Nov 27 21:34:07 2020 +0100 +++ b/libui/ui/button.c Sat Nov 28 18:00:05 2020 +0100 @@ -29,6 +29,7 @@ #include "button.h" #include "label.h" #include "theme.h" +#include "ui_p.h" static bool is_boxed(const struct button *button, const struct event_click *click) @@ -69,9 +70,9 @@ label_query(&label, &lw, &lh); if (lw > button->w) - tracef("button is too small for text: %u < %u", button->w, lw); + tracef(_("button width is too small for text: %u < %u"), button->w, lw); if (lh > button->h) - tracef("button is too small for text: %u < %u", button->h, lh); + tracef(_("button height is too small for text: %u < %u"), button->h, lh); align(ALIGN_CENTER, &label.x, &label.y, lw, lh, button->x, button->y, button->w, button->h);
--- a/libui/ui/gridmenu.c Fri Nov 27 21:34:07 2020 +0100 +++ b/libui/ui/gridmenu.c Sat Nov 28 18:00:05 2020 +0100 @@ -26,6 +26,7 @@ #include <core/texture.h> #include <core/trace.h> +#include "ui_p.h" #include "frame.h" #include "label.h" #include "gridmenu.h" @@ -74,7 +75,7 @@ /* Compute spacing between elements. */ if (hreq > menu->w) { - tracef("gridmenu width is too small: %u < %u", menu->w, vreq); + tracef(_("gridmenu width is too small: %u < %u"), menu->w, vreq); gtex->spaceh = 1; } else { hreq -= theme->padding * 2; @@ -82,7 +83,7 @@ } if (vreq > menu->h) { - tracef("gridmenu height is too small: %u < %u", menu->h, vreq); + tracef(_("gridmenu height is too small: %u < %u"), menu->h, vreq); gtex->spacev = 1; } else { vreq -= theme->padding * 2;
--- a/libui/ui/ui.c Fri Nov 27 21:34:07 2020 +0100 +++ b/libui/ui/ui.c Sat Nov 28 18:00:05 2020 +0100 @@ -16,12 +16,19 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <core/translate.h> + +#include "ui_p.h" #include "ui.h" #include "theme.h" bool ui_init(void) { +#if defined(MOLKO_WITH_NLS) + translate_init("mlk-libui"); +#endif + return theme_init(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libui/ui/ui_p.h Sat Nov 28 18:00:05 2020 +0100 @@ -0,0 +1,31 @@ +/* + * ui_p -- libui private definitions + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_UI_UI_P_H +#define MOLKO_UI_UI_P_H + +#include "sysconfig.h" + +#if defined(MOLKO_WITH_NLS) +# include <libintl.h> +# define _(s) dgettext("mlk-libui", s) +#else +# define _(s) +#endif + +#endif /* !MOLKO_UI_UI_P_H */
--- a/tests/test-map.c Fri Nov 27 21:34:07 2020 +0100 +++ b/tests/test-map.c Sat Nov 28 18:00:05 2020 +0100 @@ -159,7 +159,7 @@ * we will skip if it fails to initialize. */ - if (core_init() && window_open("test-map", 100, 100)) { + if (core_init("fr.malikania", "test") && window_open("test-map", 100, 100)) { GREATEST_RUN_SUITE(suite_basics); GREATEST_RUN_SUITE(suite_errors); }
--- a/tests/test-tileset.c Fri Nov 27 21:34:07 2020 +0100 +++ b/tests/test-tileset.c Sat Nov 28 18:00:05 2020 +0100 @@ -115,7 +115,7 @@ { GREATEST_MAIN_BEGIN(); - if (core_init() && window_open("test-tileset", 100, 100)) { + if (core_init("fr.malikania", "test") && window_open("test-tileset", 100, 100)) { GREATEST_RUN_SUITE(suite_basics); GREATEST_RUN_SUITE(suite_errors); }