Я (как и все остальные) использую NSLocalizedString
для локализации своего приложения.
К сожалению, есть несколько "недостатков" (не обязательно по вине самого NSLocalizedString), в том числе
- Нет автозаполнения для строк в Xcode. Это делает работу не только подверженной ошибкам, но и утомительной.
- В конечном итоге вы можете переопределить строку просто потому, что не знали, что эквивалентная строка уже существует (например, «Пожалуйста, введите пароль» или «Сначала введите пароль»).
- Как и в случае с автозаполнением, вам нужно «запомнить» / скопировать строки комментариев, иначе в результате
genstring
получится несколько комментариев для одной строки. - Если вы хотите использовать
genstring
после того, как вы уже локализовали некоторые строки, вы должны быть осторожны, чтобы не потерять свои старые локализации. - Одинаковые строки разбросаны по всему вашему проекту. Например, вы использовали
NSLocalizedString(@"Abort", @"Cancel action")
везде, а затем Code Review просит вас переименовать строку в,NSLocalizedString(@"Cancel", @"Cancel action")
чтобы сделать код более согласованным.
Что я делаю (и после некоторых поисков в SO я подумал, что многие люди делают это), так это иметь отдельный strings.h
файл, в котором я #define
весь код локализации. Например
// In strings.h
#define NSLS_COMMON_CANCEL NSLocalizedString(@"Cancel", nil)
// Somewhere else
NSLog(@"%@", NSLS_COMMON_CANCEL);
По сути, это обеспечивает автозавершение кода, единое место для изменения имен переменных (так что больше нет необходимости в genstring) и уникальное ключевое слово для авторефакторинга. Однако это происходит за счет целого ряда #define
операторов, которые по своей сути не структурированы (например, LocString.Common.Cancel или что-то в этом роде).
Итак, хотя это работает несколько нормально, мне было интересно, как вы, ребята, делаете это в своих проектах. Есть ли другие подходы к упрощению использования NSLocalizedString? Может быть, есть даже структура, которая инкапсулирует это?
Ответы:
NSLocalizedString
имеет несколько ограничений, но он настолько важен для Какао, что неразумно писать собственный код для обработки локализации, что означает, что вам придется его использовать. Тем не менее, небольшой набор инструментов может помочь, вот как я поступаю:Обновление файла строк
genstrings
перезаписывает ваши строковые файлы, удаляя все ваши предыдущие переводы. Я написал update_strings.py, чтобы проанализировать старый файл строк, запуститьgenstrings
и заполнить пробелы, чтобы вам не приходилось вручную восстанавливать существующие переводы. Сценарий пытается как можно точнее сопоставить существующие строковые файлы, чтобы избежать слишком большого различия при их обновлении.Именование ваших струн
Если вы используете
NSLocalizedString
как рекламируется:NSLocalizedString(@"Cancel or continue?", @"Cancel notice message when a download takes too long to proceed");
Вы можете в конечном итоге определить ту же строку в другой части кода, что может противоречить друг другу, поскольку один и тот же английский термин может иметь разное значение в разных контекстах (
OK
иCancel
приходить на ум). Вот почему я всегда использую бессмысленную строку с заглавными буквами с префиксом, зависящим от модуля, и очень точным описанием:NSLocalizedString(@"DOWNLOAD_CANCEL_OR_CONTINUE", @"Cancel notice window title when a download takes too long to proceed");
Использование одной и той же строки в разных местах
Если вы используете одну и ту же строку несколько раз, вы можете либо использовать макрос, как вы это сделали, либо кэшировать его как переменную экземпляра в вашем контроллере представления или источнике данных. Таким образом, вам не придется повторять описание, которое может устареть и стать несовместимым среди экземпляров одной и той же локализации, что всегда сбивает с толку. Поскольку переменные экземпляра являются символами, вы сможете использовать автозаполнение для этих наиболее распространенных переводов и использовать «ручные» строки для конкретных, которые в любом случае будут выполняться только один раз.
Я надеюсь, что с этими советами вы будете более продуктивны при локализации какао!
источник
genstrings
нетgestring
.Что касается автозаполнения строк в Xcode, вы можете попробовать https://github.com/questbeat/Lin .
источник
Согласен с ndfred, но я хотел бы добавить следующее:
Второй параметр можно использовать как ... значение по умолчанию !!
(NSLocalizedStringWithDefaultValue не работает должным образом с genstring, поэтому я предложил это решение)
Вот моя пользовательская реализация, использующая NSLocalizedString, которая использует комментарий как значение по умолчанию:
1. В предварительно скомпилированном заголовке (файл .pch) переопределите макрос NSLocalizedString:
// cutom NSLocalizedString that use macro comment as default value #import "LocalizationHandlerUtil.h" #undef NSLocalizedString #define NSLocalizedString(key,_comment) [[LocalizationHandlerUtil singleton] localizedString:key comment:_comment]
2. создать класс для реализации обработчика локализации
#import "LocalizationHandlerUtil.h" @implementation LocalizationHandlerUtil static LocalizationHandlerUtil * singleton = nil; + (LocalizationHandlerUtil *)singleton { return singleton; } __attribute__((constructor)) static void staticInit_singleton() { singleton = [[LocalizationHandlerUtil alloc] init]; } - (NSString *)localizedString:(NSString *)key comment:(NSString *)comment { // default localized string loading NSString * localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:key table:nil]; // if (value == key) and comment is not nil -> returns comment if([localizedString isEqualToString:key] && comment !=nil) return comment; return localizedString; } @end
3. Используйте это!
Убедитесь, что вы добавили сценарий выполнения на этапах сборки приложения, чтобы файл Localizable.strings обновлялся при каждой сборке, т.е. новая локализованная строка будет добавлена в файл Localized.strings:
Мой сценарий этапа сборки - это сценарий оболочки:
Итак, когда вы добавляете эту новую строку в свой код:
self.title = NSLocalizedString(@"view_settings_title", @"Settings");
Затем выполните сборку, ваш файл ./Localizable.scripts будет содержать эту новую строку:
/* Settings */ "view_settings_title" = "view_settings_title";
И поскольку ключ == значение для 'view_settings_title', пользовательский LocalizedStringHandler вернет комментарий, то есть «Настройки»
Вуаля :-)
источник
В Swift я использую следующее, например, для кнопки «Да» в этом случае:
NSLocalizedString("btn_yes", value: "Yes", comment: "Yes button")
Обратите внимание на использование в
value:
качестве текстового значения по умолчанию. Первый параметр служит идентификатором перевода. Преимущество использованияvalue:
параметра состоит в том, что текст по умолчанию можно изменить позже, но идентификатор перевода останется прежним. Файл Localizable.strings будет содержать"btn_yes" = "Yes";
Если
value:
параметр не использовался, то первый параметр будет использоваться как для идентификатора перевода, так и для текстового значения по умолчанию. Файл Localizable.strings будет содержать"Yes" = "Yes";
. Такое управление файлами локализации кажется странным. Особенно, если переведенный текст длинный, то и идентификатор тоже длинный. Каждый раз при изменении любого символа текстового значения по умолчанию изменяется и идентификатор перевода. Это приводит к проблемам при использовании внешних систем перевода. Под изменением идентификатора перевода понимается добавление нового текста перевода, что не всегда может быть желательным.источник
Я написал сценарий, помогающий поддерживать Localizable.strings на нескольких языках. Хотя это не помогает при автозаполнении, но помогает объединить файлы .strings с помощью команды:
Для получения дополнительной информации см. Https://github.com/hiroshi/merge_strings.
Надеюсь, некоторые из вас сочтут это полезным.
источник
Если кто-то ищет решение Swift. Вы можете проверить мое решение, которое я собрал здесь: SwiftyLocalization
Выполнив несколько шагов по настройке, вы получите очень гибкую локализацию в Google Spreadsheet (комментарий, пользовательский цвет, выделение, шрифт, несколько листов и т. Д.).
Вкратце, шаги: Таблица Google -> Файлы CSV -> Localizable.strings
Более того, он также генерирует Localizables.swift, структуру, которая действует как интерфейсы для извлечения и декодирования ключа для вас (хотя вы должны вручную указать способ декодирования String из ключа).
Почему это здорово?
Хотя есть инструменты, которые могут автоматически заполнять ваш локализуемый ключ. Ссылка на реальную переменную гарантирует, что это всегда действительный ключ, иначе он не будет компилироваться.
// It's defined as computed static var, so it's up-to-date every time you call. // You can also have your custom retrieval method there. button.setTitle(Localizables.login.button_title_login, forState: .Normal)
В проекте используется сценарий Google App Script для преобразования таблиц -> CSV и сценарий Python для преобразования файлов CSV -> Localizable.strings. Вы можете быстро взглянуть на этот примерный лист, чтобы узнать, что возможно.
источник
с iOS 7 и Xcode 5 вам следует избегать использования метода «Localization.strings» и использовать новый метод «базовой локализации». Есть несколько руководств, если вы используете Google для "базовой локализации"
Документ Apple: базовая локализация
источник
#define PBLocalizedString(key, val) \ [[NSBundle mainBundle] localizedStringForKey:(key) value:(val) table:nil]
источник
Лично я часто увлекаюсь кодированием, забывая помещать записи в файлы .strings. Таким образом, у меня есть вспомогательные сценарии, чтобы найти, что я должен вернуть в файлы .strings и перевести.
Поскольку я использую свой собственный макрос поверх NSLocalizedString, пожалуйста, просмотрите и обновите скрипт перед использованием, поскольку я предположил для простоты, что nil используется в качестве второго параметра для NSLocalizedString. Часть, которую вы хотите изменить, это
NSLocalizedString\(@(".*?")\s*,\s*nil\)
Просто замените его чем-то, что соответствует вашему макросу и использованию NSLocalizedString.
Вот сценарий, вам действительно нужна только часть 3. Остальное легче увидеть, откуда все это взялось:
// Part 1. Get keys from one of the Localizable.strings perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings // Part 2. Get keys from the source code grep -n -h -Eo -r 'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/' // Part 3. Get Part 1 and 2 together. comm -2 -3 <(grep -n -h -Eo -r 'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/' | sort | uniq) <(perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings | sort) | uniq >> fr-localization-delta.txt
Выходной файл содержит ключи, которые были найдены в коде, но не в файле Localizable.strings. Вот пример:
"MPH" "Map Direction" "Max duration of a detailed recording, hours" "Moving ..." "My Track" "New Trip"
Конечно можно отполировать еще, но думал поделится.
источник