Fixed auto-detecting locale on Windows

* localename library is now used to determine the actual locale used
 * added patched version of FindGettext.cmake to fix
   installation path of translation files
dev-ui
Piotr Dziwinski 2013-06-24 13:07:33 +02:00
parent 78c167064b
commit 3e989c96df
9 changed files with 3261 additions and 23 deletions

View File

@ -43,7 +43,7 @@ message(STATUS "Building Colobot \"${COLOBOT_VERSION_CODENAME}\" (${COLOBOT_VERS
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Include cmake directory with some additional scripts
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${colobot_SOURCE_DIR}/cmake")
set(CMAKE_MODULE_PATH "${colobot_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
# Auto-detect develpment build if not given
if(CMAKE_BUILD_TYPE AND NOT(DEV_BUILD))
@ -145,7 +145,7 @@ find_package(GLEW REQUIRED)
if (${OPENAL_SOUND})
find_package(OpenAL REQUIRED)
include("${colobot_SOURCE_DIR}/cmake/FindLibSndFile.cmake")
find_package(LibSndFile REQUIRED)
endif()
@ -209,6 +209,13 @@ set(CLIPBOARD_INCLUDE_DIR ${colobot_SOURCE_DIR}/lib/clipboard/include)
add_subdirectory(lib/clipboard)
##
# Localename
##
set(LOCALENAME_INCLUDE_DIR ${colobot_SOURCE_DIR}/lib/localename)
add_subdirectory(lib/localename)
##
# Doxygen docs
##
@ -278,7 +285,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(COLOBOT_INSTALL_BIN_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot binary directory")
set(COLOBOT_INSTALL_LIB_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot libraries directory")
set(COLOBOT_INSTALL_DATA_DIR ${CMAKE_INSTALL_PREFIX}/data CACHE PATH "Colobot shared data directory")
set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/ CACHE PATH "Colobot translations directory")
set(COLOBOT_INSTALL_I18N_DIR ${CMAKE_INSTALL_PREFIX}/lang CACHE PATH "Colobot translations directory")
set(COLOBOT_INSTALL_DOC_DIR ${CMAKE_INSTALL_PREFIX}/doc CACHE PATH "Colobot documentation directory")
endif()
else()

218
cmake/FindGettext.cmake Normal file
View File

@ -0,0 +1,218 @@
##
# Patched version of original CMake module
# Added variable GETTEXT_INSTALL_PREFIX to optionally override installation path of resulting translations
##
# - Find GNU gettext tools
# This module looks for the GNU gettext tools. This module defines the
# following values:
# GETTEXT_MSGMERGE_EXECUTABLE: the full path to the msgmerge tool.
# GETTEXT_MSGFMT_EXECUTABLE: the full path to the msgfmt tool.
# GETTEXT_FOUND: True if gettext has been found.
# GETTEXT_VERSION_STRING: the version of gettext found (since CMake 2.8.8)
#
# Additionally it provides the following macros:
# GETTEXT_CREATE_TRANSLATIONS ( outputFile [ALL] file1 ... fileN )
# This will create a target "translations" which will convert the
# given input po files into the binary output mo file. If the
# ALL option is used, the translations will also be created when
# building the default target.
# GETTEXT_PROCESS_POT( <potfile> [ALL] [INSTALL_DESTINATION <destdir>] LANGUAGES <lang1> <lang2> ... )
# Process the given pot file to mo files.
# If INSTALL_DESTINATION is given then automatically install rules will be created,
# the language subdirectory will be taken into account (by default use share/locale/).
# If ALL is specified, the pot file is processed when building the all traget.
# It creates a custom target "potfile".
# GETTEXT_PROCESS_PO_FILES( <lang> [ALL] [INSTALL_DESTINATION <dir>] PO_FILES <po1> <po2> ... )
# Process the given po files to mo files for the given language.
# If INSTALL_DESTINATION is given then automatically install rules will be created,
# the language subdirectory will be taken into account (by default use share/locale/).
# If ALL is specified, the po files are processed when building the all traget.
# It creates a custom target "pofiles".
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
# Copyright 2007 Alexander Neundorf <neundorf@kde.org>
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
find_program(GETTEXT_MSGMERGE_EXECUTABLE msgmerge)
find_program(GETTEXT_MSGFMT_EXECUTABLE msgfmt)
if(GETTEXT_MSGMERGE_EXECUTABLE)
execute_process(COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --version
OUTPUT_VARIABLE gettext_version
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (gettext_version MATCHES "^msgmerge \\(.*\\) [0-9]")
string(REGEX REPLACE "^msgmerge \\([^\\)]*\\) ([0-9\\.]+[^ \n]*).*" "\\1" GETTEXT_VERSION_STRING "${gettext_version}")
endif()
unset(gettext_version)
endif()
set(GETTEXT_INSTALL_PREFIX share/locale)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Gettext
REQUIRED_VARS GETTEXT_MSGMERGE_EXECUTABLE GETTEXT_MSGFMT_EXECUTABLE
VERSION_VAR GETTEXT_VERSION_STRING)
include(CMakeParseArguments)
function(_GETTEXT_GET_UNIQUE_TARGET_NAME _name _unique_name)
set(propertyName "_GETTEXT_UNIQUE_COUNTER_${_name}")
get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
if(NOT currentCounter)
set(currentCounter 1)
endif()
set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
math(EXPR currentCounter "${currentCounter} + 1")
set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
endfunction()
macro(GETTEXT_CREATE_TRANSLATIONS _potFile _firstPoFileArg)
# make it a real variable, so we can modify it here
set(_firstPoFile "${_firstPoFileArg}")
set(_gmoFiles)
get_filename_component(_potName ${_potFile} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
set(_addToAll)
if(${_firstPoFile} STREQUAL "ALL")
set(_addToAll "ALL")
set(_firstPoFile)
endif()
foreach (_currentPoFile ${_firstPoFile} ${ARGN})
get_filename_component(_absFile ${_currentPoFile} ABSOLUTE)
get_filename_component(_abs_PATH ${_absFile} PATH)
get_filename_component(_lang ${_absFile} NAME_WE)
set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo)
add_custom_command(
OUTPUT ${_gmoFile}
COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_absFile} ${_absPotFile}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_absFile}
DEPENDS ${_absPotFile} ${_absFile}
)
install(FILES ${_gmoFile} DESTINATION ${GETTEXT_INSTALL_PREFIX}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
set(_gmoFiles ${_gmoFiles} ${_gmoFile})
endforeach ()
if(NOT TARGET translations)
add_custom_target(translations)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME(translations uniqueTargetName)
add_custom_target(${uniqueTargetName} ${_addToAll} DEPENDS ${_gmoFiles})
add_dependencies(translations ${uniqueTargetName})
endmacro()
function(GETTEXT_PROCESS_POT_FILE _potFile)
set(_gmoFiles)
set(_options ALL)
set(_oneValueArgs INSTALL_DESTINATION)
set(_multiValueArgs LANGUAGES)
CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
get_filename_component(_potName ${_potFile} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _potBasename ${_potName})
get_filename_component(_absPotFile ${_potFile} ABSOLUTE)
foreach (_lang ${_parsedArguments_LANGUAGES})
set(_poFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.po")
set(_gmoFile "${CMAKE_CURRENT_BINARY_DIR}/${_lang}.gmo")
add_custom_command(
OUTPUT "${_poFile}"
COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${_poFile} ${_absPotFile}
DEPENDS ${_absPotFile}
)
add_custom_command(
OUTPUT "${_gmoFile}"
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_poFile}
DEPENDS ${_absPotFile} ${_poFile}
)
if(_parsedArguments_INSTALL_DESTINATION)
install(FILES ${_gmoFile} DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES RENAME ${_potBasename}.mo)
endif()
list(APPEND _gmoFiles ${_gmoFile})
endforeach ()
if(NOT TARGET potfiles)
add_custom_target(potfiles)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME( potfiles uniqueTargetName)
if(_parsedArguments_ALL)
add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
else()
add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
endif()
add_dependencies(potfiles ${uniqueTargetName})
endfunction()
function(GETTEXT_PROCESS_PO_FILES _lang)
set(_options ALL)
set(_oneValueArgs INSTALL_DESTINATION)
set(_multiValueArgs PO_FILES)
set(_gmoFiles)
CMAKE_PARSE_ARGUMENTS(_parsedArguments "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})
foreach(_current_PO_FILE ${_parsedArguments_PO_FILES})
get_filename_component(_name ${_current_PO_FILE} NAME)
string(REGEX REPLACE "^(.+)(\\.[^.]+)$" "\\1" _basename ${_name})
set(_gmoFile ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo)
add_custom_command(OUTPUT ${_gmoFile}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${_gmoFile} ${_current_PO_FILE}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
DEPENDS ${_current_PO_FILE}
)
if(_parsedArguments_INSTALL_DESTINATION)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_basename}.gmo DESTINATION ${_parsedArguments_INSTALL_DESTINATION}/${_lang}/LC_MESSAGES/ RENAME ${_basename}.mo)
endif()
list(APPEND _gmoFiles ${_gmoFile})
endforeach()
if(NOT TARGET pofiles)
add_custom_target(pofiles)
endif()
_GETTEXT_GET_UNIQUE_TARGET_NAME( pofiles uniqueTargetName)
if(_parsedArguments_ALL)
add_custom_target(${uniqueTargetName} ALL DEPENDS ${_gmoFiles})
else()
add_custom_target(${uniqueTargetName} DEPENDS ${_gmoFiles})
endif()
add_dependencies(pofiles ${uniqueTargetName})
endfunction()

View File

@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 2.8)
add_library(localename STATIC localename.c)

41
lib/localename/README.txt Normal file
View File

@ -0,0 +1,41 @@
Part of gnulib library (http://www.gnu.org/software/gnulib/)
Original source with added patch to also include LANGUAGE environment variable.
Orignal module description below
================================
Description:
Return current locale's name, according to glibc naming conventions.
Files:
lib/localename.h
lib/localename.c
m4/localename.m4
m4/intlmacosx.m4
m4/lcmessage.m4
Depends-on:
strdup
lock
configure.ac:
gl_LOCALENAME
Makefile.am:
lib_SOURCES += localename.c
Include:
"localename.h"
Link:
@INTL_MACOSX_LIBS@
$(LTLIBTHREAD) when linking with libtool, $(LIBTHREAD) otherwise
License:
LGPLv2+
Maintainer:
Bruno Haible

2864
lib/localename/localename.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
/* Determine name of the currently selected locale.
Copyright (C) 2007, 2009-2013 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef _GL_LOCALENAME_H
#define _GL_LOCALENAME_H
#ifdef __cplusplus
extern "C" {
#endif
/* Determine the current locale's name.
It considers both the POSIX notion of locale name (see functions
gl_locale_name_thread and gl_locale_name_posix) and the system notion
of locale name (see function gl_locale_name_default).
CATEGORY is a locale category abbreviation, as defined in <locale.h>,
but not LC_ALL. E.g. LC_MESSAGES.
CATEGORYNAME is the name of CATEGORY as a string, e.g. "LC_MESSAGES".
Return the locale category's name, canonicalized into XPG syntax
language[_territory][.codeset][@modifier]
The codeset part in the result is not reliable; the locale_charset()
should be used for codeset information instead.
The result must not be freed; it is statically allocated. */
extern const char * gl_locale_name (int category, const char *categoryname);
/* Determine the current per-thread locale's name, as specified by uselocale()
calls.
CATEGORY is a locale category abbreviation, as defined in <locale.h>,
but not LC_ALL. E.g. LC_MESSAGES.
CATEGORYNAME is the name of CATEGORY as a string, e.g. "LC_MESSAGES".
Return the locale category's name, canonicalized into XPG syntax
language[_territory][.codeset][@modifier]
or NULL if no locale has been specified for the current thread.
The codeset part in the result is not reliable; the locale_charset()
should be used for codeset information instead.
The result must not be freed; it is statically allocated. */
extern const char * gl_locale_name_thread (int category, const char *categoryname);
/* Determine the thread-independent current locale's name, as specified by
setlocale() calls or by environment variables.
CATEGORY is a locale category abbreviation, as defined in <locale.h>,
but not LC_ALL. E.g. LC_MESSAGES.
CATEGORYNAME is the name of CATEGORY as a string, e.g. "LC_MESSAGES".
Return the locale category's name, canonicalized into XPG syntax
language[_territory][.codeset][@modifier]
or NULL if no locale has been specified to setlocale() or by environment
variables.
The codeset part in the result is not reliable; the locale_charset()
should be used for codeset information instead.
The result must not be freed; it is statically allocated. */
extern const char * gl_locale_name_posix (int category, const char *categoryname);
/* Determine the default locale's name, as specified by environment
variables.
Return the locale category's name, or NULL if no locale has been specified
by environment variables.
The result must not be freed; it is statically allocated. */
extern const char * gl_locale_name_environ (int category, const char *categoryname);
/* Determine the default locale's name. This is the current locale's name,
if not specified by uselocale() calls, by setlocale() calls, or by
environment variables. This locale name is usually determined by systems
settings that the user can manipulate through a GUI.
Quoting POSIX:2001:
"All implementations shall define a locale as the default locale,
to be invoked when no environment variables are set, or set to the
empty string. This default locale can be the C locale or any other
implementation-defined locale. Some implementations may provide
facilities for local installation administrators to set the default
locale, customizing it for each location. IEEE Std 1003.1-2001 does
not require such a facility."
The result must not be freed; it is statically allocated. */
extern const char * gl_locale_name_default (void);
#ifdef __cplusplus
}
#endif
#endif /* _GL_LOCALENAME_H */

View File

@ -15,5 +15,6 @@ add_custom_command(OUTPUT ${_potFile}
add_custom_target(update-pot DEPENDS ${_potFile})
file(GLOB _poFiles *.po)
set(GETTEXT_INSTALL_PREFIX ${COLOBOT_INSTALL_I18N_DIR})
gettext_create_translations(${_potFile} ALL ${_poFiles})

View File

@ -185,6 +185,7 @@ ${OPENAL_SRC}
set(LIBS
CBot
clipboard
localename
${SDL_LIBRARY}
${SDLIMAGE_LIBRARY}
${SDLTTF_LIBRARY}
@ -214,6 +215,7 @@ ${PNG_INCLUDE_DIRS}
${GLEW_INCLUDE_PATH}
${Boost_INCLUDE_DIRS}
${LIBSNDFILE_INCLUDE_DIR}
${LOCALENAME_INCLUDE_DIR}
${OPTIONAL_INCLUDE_DIRS}
${CLIPBOARD_INCLUDE_DIR}
)

View File

@ -46,6 +46,7 @@
#include <libintl.h>
#include <unistd.h>
#include <getopt.h>
#include <localename.h>
template<> CApplication* CSingleton<CApplication>::m_instance = nullptr;
@ -1741,33 +1742,38 @@ void CApplication::SetLanguage(Language language)
if (locale.empty())
{
char *envLang = getenv("LANGUAGE");
if (envLang == NULL)
{
envLang = getenv("LANG");
}
const char* envLang = gl_locale_name(LC_MESSAGES, "LC_MESSAGES");
if (envLang == NULL)
{
GetLogger()->Error("Failed to get language from environment, setting default language\n");
m_language = LANGUAGE_ENGLISH;
}
else if (strncmp(envLang,"en",2) == 0)
else
{
m_language = LANGUAGE_ENGLISH;
GetLogger()->Trace("gl_locale_name: '%s'\n", envLang);
if (strncmp(envLang,"en",2) == 0)
{
m_language = LANGUAGE_ENGLISH;
}
else if (strncmp(envLang,"de",2) == 0)
{
m_language = LANGUAGE_GERMAN;
}
else if (strncmp(envLang,"fr",2) == 0)
{
m_language = LANGUAGE_FRENCH;
}
else if (strncmp(envLang,"pl",2) == 0)
{
m_language = LANGUAGE_POLISH;
}
else
{
GetLogger()->Warn("Enviromnent locale ('%s') is not supported, setting default language\n", envLang);
m_language = LANGUAGE_ENGLISH;
}
}
else if (strncmp(envLang,"de",2) == 0)
{
m_language = LANGUAGE_GERMAN;
}
else if (strncmp(envLang,"fr",2) == 0)
{
m_language = LANGUAGE_FRENCH;
}
else if (strncmp(envLang,"pl",2) == 0)
{
m_language = LANGUAGE_POLISH;
}
GetLogger()->Trace("SetLanguage: Inherit LANGUAGE=%s from environment\n", envLang);
}
else
{
@ -1777,6 +1783,7 @@ void CApplication::SetLanguage(Language language)
putenv(S_LANGUAGE);
GetLogger()->Trace("SetLanguage: Set LANGUAGE=%s in environment\n", locale.c_str());
}
setlocale(LC_ALL, "");
bindtextdomain("colobot", m_langPath.c_str());