setlocale()在iOS模拟器中不起作用?

时间:2013-03-21 18:17:52

标签: ios c unicode ios6 wchar-t

更新:奇怪的是,setlocale()仅在iOS模拟器上失败,因此我修改了问题标题。它在实际设备上运行良好。

我在iOS 6下使用本机(C / C ++)代码,我需要格式化任意wchar_t字符串。但是,在格式化包含Latin-1代码页之外的代码点的字符串时,swprintf会失败(返回值为-1且errno = EILSEQ)。

wchar_t buff[256];
swprintf(buff, 256, L"\u00A9 %ls", L"ascii"); // works
swprintf(buff, 256, L"\u03A0 %ls", L"ascii"); // will return -1

在询问相关问题here后,问题似乎是未正确设置区域设置(我已验证该解决方案在Mac OS X下运行)。但它似乎在iOS 6下没有效果:

#include <locale.h>

setlocale(LC_CTYPE,"");

按照说明here,我已手动将区域设置文件复制/添加到我的项目中,并设置PATH_LOCALE环境变量,但问题仍然存在:

NSString* resourcePath=[[NSBundle mainBundle] resourcePath];
setenv("PATH_LOCALE", [resourcePath UTF8String], 1);
setlocale(LC_CTYPE,"en_US.UTF-8");

有没有人知道如何让setlocale()在iOS 6下工作(同时Apple Store仍然接受该应用程序)?

2 个答案:

答案 0 :(得分:0)

PATH_LOCALE是语言环境文件的基本路径,每个语言环境都位于子目录中,例如:

fr / LC_TIME fr / .. zh / LC ...

因此您需要子目录,而iOS捆绑软件不支持子目录。

这样做的时候

setlocale(LC_CTYPE,“ en_US.UTF-8”);

C库在PATH_LOCALE中查找名为“ en_US.UTF-8”的目录。

我找到的解决方案是将捆绑软件中的语言环境添加为zip文件(具有整个子目录结构),在首次启动时将其解压缩到文档路径中,然后将PATH_LOCALE设置为该新目录。

NSString* documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];

    NSString* localeDir = [documentsPath stringByAppendingPathComponent:@"/locale"];
    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:localeDir];

    if (!fileExists) {
        NSString *filepath = [[NSBundle mainBundle] pathForResource:@"locale" ofType:@"zip"];
        ZipArchive *zipArchive = [[ZipArchive alloc] init];
        [zipArchive UnzipOpenFile:filepath];
        [zipArchive UnzipFileTo:documentsPath overWrite:YES];
        [zipArchive UnzipCloseFile];
    }
    setenv("PATH_LOCALE", [[NSString stringWithFormat:@"%@/locale", documentsPath] cString], 1);

这使用了必须包含在项目中的Ziparchive。

https://code.google.com/archive/p/ziparchive/

答案 1 :(得分:0)

我无法获得斯蒂芬的解决方案。但是,这两个超级简单的解决方案都对我有用:

  1. setlocale(LC_CTYPE, "UTF-8")
  2. newlocale(LC_CTYPE_MASK, "UTF-8")与带有语言环境参数的foo_l变体wchar_t类组合。

尽管iOS可能未附带完整的语言环境套件(包括en_US.UTF-8),但它似乎附带了无语言的基本UTF-8。但它仅适用于LC_CTYPE;尝试LC_ALL将失败。您当然可以使用

进行测试
char *result = setlocale(LC_TYPE, "UTF-8");
Assert(result && strcmp(result, "UTF-8") == 0);