1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

Fix #4318: Use user locale on macOS

This commit is contained in:
Marijn van der Werf
2016-08-21 21:49:55 +01:00
committed by Ted John
3 changed files with 175 additions and 91 deletions

View File

@@ -22,7 +22,10 @@
#include <dlfcn.h>
#include <errno.h>
#include <fontconfig/fontconfig.h>
#include <fnmatch.h>
#include <locale.h>
#include "../config.h"
#include "../localisation/language.h"
#include "../localisation/string_ids.h"
#include "../util/util.h"
@@ -148,6 +151,94 @@ void platform_posix_sub_resolve_openrct_data_path(utf8 *out) {
}
}
uint16 platform_get_locale_language(){
const char *langString = setlocale(LC_MESSAGES, "");
if(langString != NULL){
// The locale has the following form:
// language[_territory[.codeset]][@modifier]
// (see https://www.gnu.org/software/libc/manual/html_node/Locale-Names.html)
// longest on my system is 29 with codeset and modifier, so 32 for the pattern should be more than enough
char pattern[32];
//strip the codeset and modifier part
int length = strlen(langString);
{
for(int i = 0; i < length; ++i){
if(langString[i] == '.' || langString[i] == '@'){
length = i;
break;
}
}
} //end strip
strncpy(pattern,langString, length); //copy all until first '.' or '@'
pattern[length] = '\0';
//find _ if present
const char *strip = strchr(pattern, '_');
if(strip != NULL){
// could also use '-', but '?' is more flexible. Maybe LanguagesDescriptors will change.
// pattern is now "language?territory"
pattern[strip - pattern] = '?';
}
// Iterate through all available languages
for(int i = 1; i < LANGUAGE_COUNT; ++i){
if(!fnmatch(pattern, LanguagesDescriptors[i].locale, 0)){
return i;
}
}
//special cases :(
if(!fnmatch(pattern, "en_CA", 0)){
return LANGUAGE_ENGLISH_US;
}
else if (!fnmatch(pattern, "zh_CN", 0)){
return LANGUAGE_CHINESE_SIMPLIFIED;
}
else if (!fnmatch(pattern, "zh_TW", 0)){
return LANGUAGE_CHINESE_TRADITIONAL;
}
//no exact match found trying only language part
if(strip != NULL){
pattern[strip - pattern] = '*';
pattern[strip - pattern +1] = '\0'; // pattern is now "language*"
for(int i = 1; i < LANGUAGE_COUNT; ++i){
if(!fnmatch(pattern, LanguagesDescriptors[i].locale, 0)){
return i;
}
}
}
}
return LANGUAGE_ENGLISH_UK;
}
uint8 platform_get_locale_currency(){
char *langstring = setlocale(LC_MONETARY, "");
if (langstring == NULL) {
return platform_get_currency_value(NULL);
}
struct lconv *lc = localeconv();
return platform_get_currency_value(lc->int_curr_symbol);
}
uint8 platform_get_locale_measurement_format(){
// LC_MEASUREMENT is GNU specific.
#ifdef LC_MEASUREMENT
const char *langstring = setlocale(LC_MEASUREMENT, "");
#else
const char *langstring = setlocale(LC_ALL, "");
#endif
if(langstring != NULL){
//using https://en.wikipedia.org/wiki/Metrication#Chronology_and_status_of_conversion_by_country as reference
if(!fnmatch("*_US*", langstring, 0) || !fnmatch("*_MM*", langstring, 0) || !fnmatch("*_LR*", langstring, 0)){
return MEASUREMENT_FORMAT_IMPERIAL;
}
}
return MEASUREMENT_FORMAT_METRIC;
}
static void execute_cmd(char *command, int *exit_value, char *buf, size_t *buf_size) {
FILE *f;

View File

@@ -21,6 +21,8 @@
#include <mach-o/dyld.h>
#include "platform.h"
#include "../util/util.h"
#include "../localisation/language.h"
#include "../config.h"
bool platform_check_steam_overlay_attached() {
STUB();
@@ -191,4 +193,86 @@ bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer)
}
}
bool platform_has_matching_language(NSString *preferredLocale, uint16* languageIdentifier)
{
@autoreleasepool
{
if ([preferredLocale isEqualToString:@"en"] || [preferredLocale isEqualToString:@"en-CA"]) {
*languageIdentifier = LANGUAGE_ENGLISH_US;
return YES;
}
if ([preferredLocale isEqualToString:@"zh-CN"]) {
*languageIdentifier = LANGUAGE_CHINESE_SIMPLIFIED;
return YES;
}
if ([preferredLocale isEqualToString:@"zh-TW"]) {
*languageIdentifier = LANGUAGE_CHINESE_TRADITIONAL;
return YES;
}
// Find an exact match (language and region)
for (int i = 1; i < LANGUAGE_COUNT; i++) {
if([preferredLocale isEqualToString:[NSString stringWithUTF8String:LanguagesDescriptors[i].locale]]) {
*languageIdentifier = i;
return YES;
}
}
// Only check for a matching language
NSString *languageCode = [[preferredLocale componentsSeparatedByString:@"-"] firstObject];
for (int i = 1; i < LANGUAGE_COUNT; i++) {
NSString *optionLanguageCode = [[[NSString stringWithUTF8String:LanguagesDescriptors[i].locale] componentsSeparatedByString:@"-"] firstObject];
if([languageCode isEqualToString:optionLanguageCode]) {
*languageIdentifier = i;
return YES;
}
}
return NO;
}
}
uint16 platform_get_locale_language()
{
@autoreleasepool
{
NSArray<NSString*> *preferredLanguages = [NSLocale preferredLanguages];
for (NSString *preferredLanguage in preferredLanguages) {
uint16 languageIdentifier;
if (platform_has_matching_language(preferredLanguage, &languageIdentifier)) {
return languageIdentifier;
}
}
// Fallback
return LANGUAGE_ENGLISH_UK;
}
}
uint8 platform_get_locale_currency()
{
@autoreleasepool
{
NSString *currencyCode = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencyCode];
return platform_get_currency_value(currencyCode.UTF8String);
}
}
uint8 platform_get_locale_measurement_format()
{
@autoreleasepool
{
NSNumber *metricSystem = [[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem];
if (metricSystem.boolValue) {
return MEASUREMENT_FORMAT_METRIC;
}
return MEASUREMENT_FORMAT_IMPERIAL;
}
}
#endif

View File

@@ -33,8 +33,6 @@
#include "../util/util.h"
#include "platform.h"
#include <dirent.h>
#include <fnmatch.h>
#include <locale.h>
#include <sys/time.h>
#include <time.h>
#include <fts.h>
@@ -795,66 +793,6 @@ void platform_get_user_directory(utf8 *outPath, const utf8 *subDirectory)
log_verbose("outPath + subDirectory = '%s'", buffer);
}
uint16 platform_get_locale_language(){
const char *langString = setlocale(LC_MESSAGES, "");
if(langString != NULL){
// The locale has the following form:
// language[_territory[.codeset]][@modifier]
// (see https://www.gnu.org/software/libc/manual/html_node/Locale-Names.html)
// longest on my system is 29 with codeset and modifier, so 32 for the pattern should be more than enough
char pattern[32];
//strip the codeset and modifier part
int length = strlen(langString);
{
for(int i = 0; i < length; ++i){
if(langString[i] == '.' || langString[i] == '@'){
length = i;
break;
}
}
} //end strip
strncpy(pattern,langString, length); //copy all until first '.' or '@'
pattern[length] = '\0';
//find _ if present
const char *strip = strchr(pattern, '_');
if(strip != NULL){
// could also use '-', but '?' is more flexible. Maybe LanguagesDescriptors will change.
// pattern is now "language?territory"
pattern[strip - pattern] = '?';
}
// Iterate through all available languages
for(int i = 1; i < LANGUAGE_COUNT; ++i){
if(!fnmatch(pattern, LanguagesDescriptors[i].locale, 0)){
return i;
}
}
//special cases :(
if(!fnmatch(pattern, "en_CA", 0)){
return LANGUAGE_ENGLISH_US;
}
else if (!fnmatch(pattern, "zh_CN", 0)){
return LANGUAGE_CHINESE_SIMPLIFIED;
}
else if (!fnmatch(pattern, "zh_TW", 0)){
return LANGUAGE_CHINESE_TRADITIONAL;
}
//no exact match found trying only language part
if(strip != NULL){
pattern[strip - pattern] = '*';
pattern[strip - pattern +1] = '\0'; // pattern is now "language*"
for(int i = 1; i < LANGUAGE_COUNT; ++i){
if(!fnmatch(pattern, LanguagesDescriptors[i].locale, 0)){
return i;
}
}
}
}
return LANGUAGE_ENGLISH_UK;
}
time_t platform_file_get_modified_time(const utf8* path){
struct stat buf;
if (stat(path, &buf) == 0) {
@@ -863,35 +801,6 @@ time_t platform_file_get_modified_time(const utf8* path){
return 100;
}
uint8 platform_get_locale_currency(){
char *langstring = setlocale(LC_MONETARY, "");
if (langstring == NULL) {
return platform_get_currency_value(NULL);
}
struct lconv *lc = localeconv();
return platform_get_currency_value(lc->int_curr_symbol);
}
uint8 platform_get_locale_measurement_format(){
// LC_MEASUREMENT is GNU specific.
#ifdef LC_MEASUREMENT
const char *langstring = setlocale(LC_MEASUREMENT, "");
#else
const char *langstring = setlocale(LC_ALL, "");
#endif
if(langstring != NULL){
//using https://en.wikipedia.org/wiki/Metrication#Chronology_and_status_of_conversion_by_country as reference
if(!fnmatch("*_US*", langstring, 0) || !fnmatch("*_MM*", langstring, 0) || !fnmatch("*_LR*", langstring, 0)){
return MEASUREMENT_FORMAT_IMPERIAL;
}
}
return MEASUREMENT_FORMAT_METRIC;
}
uint8 platform_get_locale_temperature_format(){
// LC_MEASUREMENT is GNU specific.
#ifdef LC_MEASUREMENT