Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Локализации iOS-приложений (Я.Субботник, Минск,...
Search
Andrey Subbotin
June 04, 2012
Technology
110
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Локализации iOS-приложений (Я.Субботник, Минск, 2 июня 2012 г.)
Andrey Subbotin
June 04, 2012
More Decks by Andrey Subbotin
See All by Andrey Subbotin
Hello world: что кроется за поворотом
eploko
0
46
Автоматизация локализации iOS-приложений
eploko
1
410
Other Decks in Technology
See All in Technology
パッチ更新でterraform initが落ちた日
grimoh
1
140
「Docker Desktop不要の時代」は 来たのか?
ueponx
0
770
hackers_champloo_2026_tidb
makocchi
0
160
スキマバイトという雇用形態は存在しないので、雇用期間1日のアルバイト契約を事業者とワーカーが結ぶ手続きを支えるのがタイミーなんです
akitoshiga
0
200
ストレスなくAIと付き合いたい!こんなときどうしてる?
namiki64
3
520
触りたくないデータに、どう触るか AI時代のRBACアクセスガバナンス
ivry_presentationmaterials
0
260
PHPカンファレンス関西の招待状 / Invitation to PHP Conference Kansai
ykanoh
0
110
二歩目のフロントエンド・ウェブアクセシビリティ
camiha
2
590
Rustuna: Rustによる高速なOptuna実装
pfn
PRO
0
190
CTO Night|NotionのAIエージェントとFDE
kzkhykw1991
0
110
TinyGoでオブザーバビリティ?OpenTelemetryはTinyGoで使えるのか / Is OpenTelemetry available in TinyGo environment?
ymotongpoo
2
140
今さら理解するウェブフォントver.2026
takanorip
3
790
Featured
See All Featured
Scaling GitHub
holman
464
140k
Un-Boring Meetings
codingconduct
0
460
Writing Fast Ruby
sferik
630
63k
Heart Work Chapter 1 - Part 1
lfama
PRO
10
37k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
Designing Powerful Visuals for Engaging Learning
tmiket
1
610
Building Flexible Design Systems
yeseniaperezcruz
330
41k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.5k
Fantastic passwords and where to find them - at NoRuKo
philnash
53
4k
Unsuck your backbone
ammeep
672
58k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
600
It's Worth the Effort
3n
188
29k
Transcript
Я.Субботник, Минск, 2 июня 2012 года Разработчик, Мобильные Яндекс.Карты (iOS)
Андрей Субботин Локализации iOS-приложений
Can't read, won't buy. 2
52,4% не покупают продукт на чужом языке. 60% — для
Франции, Японии и России. 89,3% — если английский знают плохо. 3
4
http://bit.ly/whylocalize 5
Интернационализация i18n = подготовка продукта к локализации 6
Локализация L10n = адаптация продукта к конкретному языку и местности
7
8 Локализация L10n Понятный язык интерфейса. Дата и время в
привычном формате. Корректная сортировка списков. Поддержка местных единиц измерения. Правильное форматирование чисел.
Что локализуется в приложении? Текстовые строки. XIB-файлы. Изображения, аудио. 9
Подготовка строк к локализации 10
= ваш друг! 11 NSLocalizedString
NSLog(NSLocalizedString(@"Some sample text", @"A text string to be output to
the logs.")); 12
NSLog(NSLocalizedString(@"Some sample text", @"A text string to be output to
the logs.")); 13 2012-03-06 08:10:05.433 L10nSample[15433:f803] Some sample text 2012-03-06 08:11:02.117 L10nSample[15438:f903] Некий примерный текст
= тоже ваш друг! NSFormatter Data Formatting Guide → 14
Выделение строк 15
*.m → Localizable.strings $ genstrings *.m -o Resources/en.lproj 16
en.lproj/Localizable.strings /* A text string to be output to the
logs. */ "Some sample text" = "Some sample text"; /* A text string to be output to the logs. */ "Some sample text" = "Некий примерный текст"; 17 ru.lproj/Localizable.strings
Выделение строк из XIB 18
$ ibtool --export-strings-file \ en.lproj/ViewController.strings \ en.lproj/ViewController.xib 19 *.xib →
*.strings
/* Class = "IBUIButton"; normalTitle = "Welcome!"; ObjectID = "8";
*/ "8.normalTitle" = "Welcome!"; 20 en.lproj/ViewController.strings
Вмерживание переводов обратно 21
$ ibtool --import-strings-file \ en.lproj/ViewController.strings \ en.lproj/ViewController.xib \ --write en.lproj/ViewController.xib
22 *.strings → *.xib
Инкрементальное обновление XIB'ов 23
Создали en.XIB. 24 А теперь что?! Локализовали en.XIB → ru.XIB.
Добавили новую кнопку в en.XIB.
$ ibtool --previous-file en.lproj/Window.old.xib --incremental-file ru.lproj/Window.old.xib --strings-file ru.lproj/Window.strings --localize-incremental --write
ru.lproj/Window.xib en.lproj/Window.new.xib 25 en.xib → ru.xib
Храните предыдущие версии XIB файлов. 26 Не правьте руками локализованные
XIB файлы.
Переводчики Понимают английский. Не всегда понимают русский. Не используют Xcode
и не редактируют XIB. Не знают контекста перевода без вашей помощи. 27
Tanker = web-сервис = API для загрузки и выгрузки переводов
28
Yoda 29 Babelfish
Babelyoda 30 избавляет от рутинной ручной работы сводит количество багов
при локализации к минимуму
31 генерирует .strings из кода и XIB’ов загружает .strings в
Tanker забирает из Tanker’а свежие переводы обновляет XIB файлы аккуратно все коммитит в git PROFIT!!
Babelyoda 32 = библиотека для работы с .strings, genstrings и
ibtool
Babelfile 33 ...по аналогии с Makefile, Gemfile, Rakefile и т.п.
= единое место конфигурации.
Babelyoda::Specification.new do |s| s.name = 'YandexMaps' s.development_language = :en s.localization_languages
= [:ru, :uk, :tr] s.engine = Babelyoda::Tanker.new do |t| t.token = ENV['TANKER_TOKEN'] t.project_id = 'myak_iphone' t.endpoint = ENV['TANKER_HOST'] end s.scm = Babelyoda::Git.new s.source_files = FileList['{Classes,Shared}/**/*.{m,mm,h}'] s.resources_folder = 'Resources' s.xib_files = FileList['Resources/**/en.lproj/*.xib'] s.strings_files = FileList['Resources/**/en.lproj/*.strings'] end 34
One command to rule them all! 35 $ rake babelyoda
$ rake -T rake babelyoda rake babelyoda:create_keysets rake babelyoda:drop_empty_strings rake
babelyoda:drop_orphan_keys rake babelyoda:drop_orphan_keysets rake babelyoda:extract rake babelyoda:extract_strings rake babelyoda:extract_xib_strings rake babelyoda:fetch_strings rake babelyoda:initBabelfile rake babelyoda:localize_xibs rake babelyoda:pull rake babelyoda:push rake babelyoda:remote:drop_keysets rake babelyoda:remote:list rake babelyoda:verify 36
#!/bin/bash function verify { if [ $CONFIGURATION == 'AppStore' ]
; then rvm rvmrc trust . && rvm rvmrc load . && bundle \ && bundle exec rake babelyoda:verify return $? fi return 0 } git submodule update --init --recursive && verify 37 yxbuildkit-prebuild.sh
http://bit.ly/yandextool 38 Available on GitHub!
Плюрализация хоррор стори 39
I scanned 12 directories. 40
NSLog(@"I scanned %g directories.", directoryCount); 41
I scanned 1 directories. 42
NSLog(@"I scanned %g %@.", directoryCount, directoryCount == 1 ? @"directory"
: @"directories", ); 43
I scanned 1 directory. 44
NSLog( NSLocalizedString(@"I scanned %g %@.", @”Text to show the number
of directories scanned”), dirScanCount, dirScanCount == 1 ? NSLocalizedString(@"directory", @”Single directory”) : NSLocalizedString(@"directories", @”Plural directories”) ); 45
46 Как это видит переводчик?
47 "I scanned %g %@." "directory" "directories" "Я просканировал %g
%@." "папка" "каталоги"
Я отсканировал 1 папка. 48
Я отсканировал 5 каталоги. 49
NSLog( dirScanCount == 1 ? NSLocalizedString("I scanned %g directory.", @”Blah”)
: NSLocalizedString("I scanned %g directories.", @”Blah”), dirScanCount ); 50
NSString *pluralTransfers = NSLocalizedString(@"%d changes", @"The number of changes shown
in the route description"); 51
NSString *forms[4] = {0}; forms[0] = NSLocalizedString(@"%d change", @"Blah"); forms[1]
= NSLocalizedString(@"%d changes", @"Blah"); forms[2] = NSLocalizedString(@"%d changes", @"Blah"); forms[3] = NSLocalizedString(@"%d changes", @"Blah"); int form = YXPluralFormForN(self.transfersCount); NSString *pluralTransfers = forms[i]; 52
int YXPluralFormForRU(NSInteger n) { // One - 1, 21, 31,
... // Some - 2-4, 22-24, 32-34 ... // Many - 5-20, 25-30, ... NSInteger n10 = n % 10; if ((n10 == 1) && ((n == 1) || (n > 20))) { return 0; } else if ((n10 > 1) && (n10 < 5) && ((n > 20) || (n < 10))) { return 1; } else { return 2; } } 53
54 Как это видит переводчик?
55 "%d change" "%d changes" "%d changes" "%d changes"
NSString *forms[4] = {0}; forms[0] = NSLocalizedString(@"NumberChanges0", @"Blah"); forms[1] =
NSLocalizedString(@"NumberChanges1", @"Blah"); forms[2] = NSLocalizedString(@"NumberChanges2", @"Blah"); forms[3] = NSLocalizedString(@"NumberChanges3", @"Blah"); int form = YXPluralFormForN(self.transfersCount); NSString *pluralTransfers = forms[i]; 56
57 Как это видит переводчик?
58 "NumberChanges0" "NumberChanges3" "NumberChanges2" "NumberChanges1"
genstrings “магия” 59
NSLocalizedString(@"%[one, some, many, none]d changes", @"The number of changes shown
in the route description"); 60
/* The number of changes shown in the route description
*/ "%[one]d changes" = "%d changes"; "%[some]d changes" = "%d changes"; "%[many]d changes" = "%d changes"; "%[none]d changes" = "%d changes"; 61 Localizable.strings /* The number of changes shown in the route description */ "%[one]d changes" = "%d остановка"; "%[some]d changes" = "%d остановки"; "%[many]d changes" = "%d остановок"; "%[none]d changes" = "";
62 "%[one, some, many, none]d changes" "%[some]d changes"
“Хитрости” 63
64 Английский текст в качестве ключа NSLocalizedString(@"Tap Here", @"Action button
title"); NSLocalizedString(@"TapButtonTitle", @"Action button title");
65 Английский текст в качестве ключа WelcomeButtonTitle WelcomeTitle ButtonTitleWelcome WelcomeTITLE
WelcomeBtnTitle
66 Различные контексты Edit = Править Edit = Изменить Edit
= Переименовать
67 Различные контексты NSLocalizedStringFromTable (<#key#>, <#tbl#>, <#comment#>) NSLocalizedStringFromTable (@”Edit”,@”Common”,@”Blah”) NSLocalizedStringFromTable
(@”Edit”,@”Buttons”,@”Blah”)
68 Склеивание строк NSString *part1 = NSLocalizedString(@"People in the room",
@"Part 1"); NSString *part2 = NSLocalizedString(@"%d", @"Part 2"); NSString *halfResult = [NSString stringWithFormat:@"%@: %@", part1, part2]; NSString *result = [NSString stringWithFormat:halfResult, 5]; ɿ̑ਓ
69 Склеивание строк NSLocalizedString( @"People in the room: %[one, some,
many, none]d", @"Blah blah"); ɿ̑ਓ
WTF!? 70
71 WTF!?
72 WTF!?
73 WTF!?
74 WTF!?
75 WTF!? WTF!? WTF!?
76 WTF!?
77 WTF!? WTF!?
Разработчик, Мобильные Яндекс.Карты (iOS)
[email protected]
@eploko Андрей Субботин