setlocale() не работает в симуляторе iOS?

Обновление: как ни странно, setlocale() не работает только в симуляторе iOS, поэтому я изменил заголовок вопроса. Он отлично работает на реальных устройствах.

Я работаю с собственным кодом (C/C++) под iOS 6, и мне нужно отформатировать произвольные строки 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

Задав соответствующий вопрос здесь, проблема заключается в том, что языковой стандарт установлен неправильно (я убедился, что решение работает в Mac OS X). Но, похоже, это не влияет на iOS 6:

#include <locale.h>

setlocale(LC_CTYPE,"");

Следуя инструкциям здесь, я скопировал/добавил локальные файлы вручную в мой проект и установить переменную среды 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)?


person Xaxx    schedule 21.03.2013    source источник


Ответы (2)


Я не мог заставить решение Стефана работать. Но оба этих сверхпростых решения сработали для меня:

  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);
person David Pritchard    schedule 20.06.2019

PATH_LOCALE — это базовый путь для файлов локали, каждая локаль находится в подкаталоге, например:

fr/LC_TIME fr/.. en/LC...

Итак, вам нужны подкаталоги, а пакеты iOS не поддерживают подкаталоги.

Когда вы делаете

setlocale(LC_CTYPE,"en_US.UTF-8");

Библиотека C ищет каталог с именем "en_US.UTF-8" в PATH_LOCALE.

Решение, которое я нашел, состоит в том, чтобы добавить локали в пакет в виде 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/

person stephane k.    schedule 19.12.2018