Отображение локализованной информации о драйверах

Часто повторный факт в Дарвинской документации - то, что расширение ядра является пакетом. Что это означает, и каковы импликации?

Пакет является каталогом со строго определенной внутренней структурой, (обычно) содержащей исполняемый код и ресурсы та поддержка тот код. Пакет на OS X является основной формой упаковки для исполнимых программ в файловой системе. Приложения и платформы являются пакетами, как все другие загружаемые пакеты, такие как расширения ядра. Несмотря на то, что некоторые исполнимые программы не являются пакетами — прежде всего инструменты командной строки, некоторые библиотеки и приложения CFM-PEF — они находятся определенно в меньшинстве. Средство поиска представляет большинство пакетов пользователям непрозрачно как файл.

Пакет может быть программно представлен объектом NSBundle (для кода Какао) или непрозрачным типом CFBundle (для всех других сред приложения). APIs NSBundle и CFBundle разрешает Вашей исполнимой программе получать доступ и управлять ресурсами в представленном пакете.

Среди преимуществ, которые форма пакета упаковки дает исполнимым программам, интернационализация. Интернационализация является механизмом, которыми исполнимыми программами на хранилище OS X локализованные ресурсы в пакетах и получают доступ к ним для представления их в графическом интерфейсе пользователя. Локализованные ресурсы - те, которые были переведены и адаптированы на определенные языки и локали; текст, изображения и звуки среди часто локализующихся ресурсов. OS X пытается представить те локализации, соответствующие предпочтение языка пользователя.

Драйверы устройств и другие расширения ядра иногда должны локализовать информацию, выведенную на экран пользователям во время задач, требующих ввода данных пользователем, такого как конфигурация и установка. Но необходимо помнить, что расширения ядра являются различной породой пакета. Исполняемый код в этих пакетах загружается в ядро, и код ядра, по определению, не играет прямую роль в пользовательских интерфейсах. Если расширение ядра содержит локализованные ресурсы для дисплея, оно должно иметь агент пространства пользователя, чтобы сделать отображение для него. Во многих случаях расширение ядра будет иметь вспомогательное приложение или предпочтительную область для представления локализованного пользовательского интерфейса.

Можно было бы спросить: почему бы не помещать все локализованные ресурсы во вспомогательное приложение вместо расширения ядра? Выполнение так, казалось бы, упростило бы определять местоположение ресурсов. Когда существует только одно расширение ядра на вспомогательное приложение, это может быть истиной. Но обычно вспомогательное приложение ответственно за семейство расширений ядра, и текущие и ожидаемые продукты. Если приложение должно содержать все локализованные ресурсы, оно должно иметь предварительные знания каждого расширения ядра, о котором оно могло бы вывести на экран информацию. Поскольку это непрактично, имеет больше смысла для расширения ядра инкапсулировать свои собственные локализации.

Этот раздел обеспечивает обзор интернационализации расширений ядра и описывает специальный APIs и процедуры, кодирующие в пространстве пользователя, должен использовать для доступа к локализованным ресурсам, сохраненным в этих пакетах.

Интернационализация расширений ядра

Интернационализация Вашего расширения ядра является довольно безболезненным процессом. Необходимо установить файлы проекта определенным способом, и Вы, возможно, должны изменить код. Конечно, Вы, должно быть, локализовали ресурсы для помещения в проект. Это означает, что кто-то должен завершить все необходимые переводы и адаптацию следующих ресурсов:

Этот раздел суммирует шаги, которые необходимо выполнить для интернационализации расширения ядра. Для всех однофайловых ресурсов, таких как изображения, звуки, файлы пера и файлы справки, интернационализация является простым вопросом помещения файлов ресурсов в определенных подкаталогах расширения ядра. В Вашем коде пространства пользователя Вам, вероятно, тогда придется использовать CFBundle (или NSBundle) APIs для получения пути к файлу ресурсов в текущей локализации до загрузки того ресурса. Процедура для интернационализации строк пользовательского интерфейса немного более включается; эта процедура получена в итоге в Интернационализации Строк.

Создание и заполнение каталогов локализации

При рассмотрении внутренней структуры простого интернационализировавшего расширения ядра в файловой системе Вы могли бы видеть что-то вроде этого:

MyDriver.kext/
    Contents/
        MacOS/              // contains kernel binary
        Resources/
            Logo.tiff           // non-localized resource
            en.lproj/
                Stop.tiff       // English-localized resource
            fr.lproj/
                Stop.tiff       // French-localized resource

Как Вы видите, ресурсы пакета идут (достаточно логически) в Resources подкаталог пакета. Ресурсы на верхнем уровне Resources нелокализуются и таким образом выведены на экран в пользовательском интерфейсе независимо от предпочтения языка зарегистрированного пользователя. Локализованные ресурсы (эти два файла образа называют Stop.tiff в вышеупомянутых примерах), помещаются в подкаталоги Resources; каждый из этих каталогов имеет расширение .lproj и имя, которое является или английским именем главного языка или сокращением ISO 639 для языка (такого как «en»). Имя может также иметь суффикс, который является сокращением ISO 3166 для локали (например, «en_US» для английского языка США). Когда приложение должно вывести на экран локализованный ресурс, OS X получает предпочтения языка зарегистрированного пользователя — это - сортированный список предпочтительного набора языков через область International Установок системы — и теряет работоспособность список, пока это не находит первый язык, соответствующий один из .lproj каталоги локализации в пакете. Это - то, как в основном работает механизм интернационализации.

Можно создать внутреннюю структуру локализации пакета вручную, но более удобно позволить приложению Разработчика Проекта выполнить большую часть работы для Вас. Процедура является довольно прямой. В Разработчике Проекта:

  1. Создайте группу для локализованных и нелокализованных ресурсов.

    Щелкните по вкладке Files. Choose New Group из Меню проектов и имени новая группа. (Разрешение, имя это «Снабжает ресурсами».)

  2. Добавьте ресурс к группе.

    Выберите Add Files из Меню проектов. В браузере найдите и выберите файл, содержащий звук, изображение, текст или другой ресурс. Когда этот файл появится в области Files Разработчика Проекта, перетащите его в группу Ресурсов, при необходимости.

  3. Отметьте атрибут локализации файла.

    1. Выберите файл и выберите Show Info из Меню проектов.

    2. От Локализации и Платформ раскрывающийся список, выберите Add Localized Variant.

    3. В листе, затем появляющемся, или выбирающем имя языка из поля комбинированного списка или, если локализация для некоторого другого языка, вводят сокращение ISO 639 в текстовом поле. Нажать «OK».

    4. Если Вы позже решаете, что ресурс не должен быть локализован, выбрать его и выбрать Make Global из Локализации и Платформ раскрывающийся список.

Завершите вышеупомянутую процедуру для каждого ресурса, локализованного и нелокализованного, который Вы хотите включенный в Ваш проект. Когда Вы разработаете проект, Разработчик Проекта создаст .lproj каталог для каждой локализации и помещенный все ресурсы определяется для той локализации в каталоге. Имя и расширение файла ресурсов должны быть точно тем же для каждой локализации.

Интернационализация строк

Если приложение получает локализованные строки для своего пользовательского интерфейса от файла пера, Вы должны только хранить локализованные файлы пера в каждом .lproj каталог расширения ядра для интернационализации их. Однако, если приложение должно вывести на экран локализованные строки для расширения ядра программно, у Вас должен быть строковый файл в каждом .lproj каталог расширения ядра. Строковый файл так называем, потому что его расширение .strings; стандартное имя перед расширением Localizable, но это не требование.

Формат строкового файла является простым значением ключа, соединяющимся для каждой строковой записи; запись завершается точкой с запятой и возвратом каретки (т.е. одна запись на строку). Ключ является строкой на языке разработки; значение является локализованной строкой. Между ключом и значением знак «равно». Например:

/* a comment */
/* "key" = "value"; */
"Yes" = "Oui";
"The same text in English" = "Le meme texte en francais";

Как только Вы создали файл локализованных строк, помещал его в надлежащее .lproj каталог (как описано в Создании и Заполнении Каталогов Локализации). Следующий шаг должен изменить код приложения для отображения локализованной строки. В каждой точке, где локализованная строка необходима, используйте макрос CFCopyLocalizedString (и варианты), если Вы используете APIs CFBundle; при использовании NSBundle Какао используйте NSLocalizedString макрос (и варианты) вместо этого. В самой простой версии макроса Вы указываете два параметра: ключ и комментарий. Например:

CFStringRef locstr = CFCopyLocalizedString(CFSTR("Yes"), CFSTR("");

Если предпочтение языка зарегистрированного пользователя является французским, переменная locstr содержит значение «Oui». Комментарий там по определенной причине. Вместо того, чтобы создать строковый файл с нуля, можно поместить все требуемые CFCopyLocalizedString (или NSLocalizedString) вызовы в Вашем коде приложения сначала. В параметре комментария дайте любые инструкции переводчику для строки. Тогда работайте genstrings утилита командной строки на Вашем файле исходного кода для генерации строкового файла. Можно тогда дать копию сгенерированного файла к переводчику для каждой локализации.

Получение пути к KEXT от пространства пользователя

Если Вы будете ответственны за код пространства пользователя, который должен вывести на экран локализованную информацию Вашего расширения ядра, то необходимо будет получить путь к KEXT. CFBundle и NSBundle требуют, чтобы путь к пакету создал объект пакета, который необходимо программно получить доступ к ресурсам пакета.

Решение этого состоит в том, чтобы передать CFBundleIdentifier из Вашего KEXT специальному менеджеру KEXT функционируют для получения пути пакета. Менеджер KEXT определяет следующую функцию с этой целью (в IOKit.framework/Headers/kext/KextManager.h):

CFURLRef KextManagerCreateURLForBundleIdentifier(
    CFAllocatorRef allocator,
    CFStringRef    bundleIdentifier);

KextManagerCreateURLForBundleIdentifier функционируйте возвращает объект CFURLRef представление пути к любому KEXT, в настоящее время устанавливаемому в /System/Library/Extensions идентифицированный переданным - в CFBundleIdentifier. Для параметра CFAllocatorRef можно получить текущее средство выделения по умолчанию с вызовом к CFAllocatorGetDefault.

Как только у Вас есть путь к расширению ядра (как объект CFURLRef), можно создать объект пакета (CFBundleRef) из него с помощью следующей функции CFBundle:

CF_EXPORT
CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL);

Можно заставить пакет возразить последующей цели требований возврата локализованных ресурсов, таких как строки, изображения и значки.