Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Локализации iOS-приложений (Я.Субботник, Минск,...
Search
Andrey Subbotin
June 04, 2012
Technology
100
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
43
Автоматизация локализации iOS-приложений
eploko
1
410
Other Decks in Technology
See All in Technology
AGENTS.mdとSkillsで始めるAIエージェント活用
sonoda_mj
3
220
Kiroで書いた 設計書 が AI レビューの 採点基準 になる
ezaki
0
110
気軽に使える"情報のハブ"としてのNotion活用 〜フロー情報の集積点 と、 Claude Code × Notion AI〜
syucream
1
140
連合学習と機密コンピューティング
lycorptech_jp
PRO
0
120
GitHub Copilot 最新アップデート – 「一歩先」の実践活用術
moulongzhang
4
1.1k
【Snowflake Summit 2026 Recap!!】Snowflake Summit Deep Dive: Security & Governance
civitaspo
1
220
なぜ Platform Engineering の土台に Kubernetes を選ぶのか
r4ynode
2
650
「エンジニア進化論」2028年の開発完全自動化、エンジニアはどう進化するか
cyberagentdevelopers
PRO
6
5.3k
プロダクト開発から業務改善コンサルまで。事業全体へ「染み出す」ことで広がるエンジニアの可能性
ham0215
0
130
SONiCの統計情報を取得したい
sonic
0
180
自宅LLMの話
jacopen
1
600
AIっぽい文章を採点して人間らしく直すアプリを作ってみた
yama3133
2
200
Featured
See All Featured
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
180
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
How GitHub (no longer) Works
holman
316
150k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.1k
How to make the Groovebox
asonas
2
2.2k
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
170
ラッコキーワード サービス紹介資料
rakko
1
3.7M
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
1
200
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 Андрей Субботин