问题
At my workplace, our app determines the locale of the user session by using a code that is similar to below (though there are various layers of code it passes through before it reaches here at the time of startup, so the problem is/may not evident by running the code below)
#include <CoreFoundation/CoreFoundation.h>
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// Reference release
struct reference_close
{
void operator()(const void *ref) const
{
CFRelease(static_cast<CFTypeRef>(ref));
}
}; // end of reference_close structure
typedef std::unique_ptr<const void, reference_close> reference_uptr;
std::string get_user_locale()
{
reference_uptr ref_ptr(CFLocaleCopyCurrent());
CFLocaleRef locale_ref(static_cast<CFLocaleRef>(ref_ptr.get()));
if (locale_ref == nullptr)
{
return std::string();
}
const size_t default_size(128);
std::vector<char> buff(default_size);
CFStringRef str_ref(CFLocaleGetIdentifier(locale_ref));
if (str_ref != nullptr)
{
CFIndex len(CFStringGetLength(str_ref) + 1);
if (len > boost::numeric_cast<CFIndex>(default_size))
{
buff.resize(len);
}
buff[0] = 0;
if (!CFStringGetCString(str_ref, &buff[0], len, kCFStringEncodingISOLatin1))
{
return std::string();
}
}
return std::string(&buff[0]);
} // end of get_user_locale()
int main()
{
std::cout << "get_user_locale() : "<<get_user_locale() << std::endl;
return 0;
}
The app has a well defined bundle structure with necessary resources and localization resource directories e.g Contents/Resources/ja.lproj
Lately, we are facing an issue wherein we do the following
1) Change the system language and country in the preferences e.g. change from en_US to ja_JP
2) Reboot the machine
3) Launch the app and see the erroneous output e.g en_JP
4) Re-launch the app to get the correct answer as ja_JP
I have read the documentation of CFLocaleCopyCurrent which states that
Settings you get from this locale do not change as a user's preferences are changed so that your operations are consistent. Typically you perform some operations on the returned object and then release it. Since the returned object may be cached, you do not need to hold on to it indefinitely.
I also checked the another documentation on lifetime of CFLocale which states that
The object you get back from CFLocaleCopyCurrent does not change when the user changes their Preferences settings. Moreover, the object itself may be cached by the runtime system, so successive calls of CFLocaleCopyCurrent may return the same object, even if a user has changed preference settings. If you want to ensure that your locale settings are consistent with user preferences, you must synchronize preferences and get a new locale object with CFLocaleCopyCurrent.
Given this info, I tried to incorporate CFPreferencesSynchronize
and/or CFPreferencesSynchronize
in the app code (just before I call the CFLocaleCopyCurrent
) to get the most updated locale. But no luck.
Do I need to do anything extra to make sure that I get the most recent/updated value of locale object from the system preferences ?
回答1:
Use [NSLocale autoupdatingCurrentLocale] which will change as the user changes their locale settings, but as NSLocale
is an Objective-C class you will need to implement glue code as Objective-C++.
Here is some untested example code, giving you the idea:
Create a file called AppleLocale.mm
(unless of course your project is for Apple platforms only so doesn't need the Apple
name prefix).
#include <Foundation/Foundation.h>
std::string get_user_locale()
{
NSLocale* locale = [NSLocale autoupdatingCurrentLocale];
return std::string([[locale localeIdentifier] UTF8String]);
}
Note: You'll need a function prototype in some header as well, of course.
来源:https://stackoverflow.com/questions/58713505/cflocalecopycurrent-stale-value