스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
다국어를 지원하는 앱 빌드하기
다국어 사용자를 위해 적절하고 효과적인 앱 기능을 제공하세요. 텍스트 입력, 표시, 검색, 서식 적용 등을 위한 모범 사례를 확인해 보세요. 키보드 언어를 변환하지 않고도 다국어를 입력할 수 있게 지원하는 방법을 자세히 알아보고, 로컬라이제이션을 더욱 손쉽게 만들어 주는 String Catalog의 최신 개선 사항도 확인해 보세요.
챕터
- 0:00 - Introduction
- 2:24 - Input
- 8:08 - Display
- 11:01 - Localization
- 16:07 - Wrap-up
리소스
관련 비디오
WWDC24
WWDC23
WWDC21
WWDC20
-
다운로드
안녕하세요, آداب(ādāb) नमस्ते(namaste), 大家好(dàjiāhǎo) 저는 Karan입니다 이 영상에서는 다국어 지원 앱을 제작하는 법을 알아보겠습니다 오늘날 전 세계 사람들은 자라면서 2개 언어를 학습하거나 여러 언어를 접합니다 밴쿠버에서 읽고 싶은 책을 찾을 때 타이페이에서 빙수를 먹거나 델리에서 지하철을 탈 때 다국어 사회에서 우리는 서로 다른 수십 개 언어로 이야기하고, 문자를 보내고 읽고, 듣는 것을 경험하죠 매일 앱으로 사람들과 소통하고 일지를 작성하고 영화를 보고, 책을 읽으며 우리가 쓰는 모든 언어에 맞게 앱이 작동할 것이라 기대합니다
그런 취지에서 오늘은 다국어 사용자를 효과적으로 지원하는 앱을 제작하는 팁을 공유하겠습니다 해당 내용을 말씀드리기 전에 우선 Apple에서 지금까지 진행한 여러 작업을 소개할까 합니다 올해 Apple은 다국어 경험의 기준을 높이는 여러 새로운 기능을 도입할 예정이며 기존 기능에서도 더 많은 언어를 지원하도록 확장할 계획입니다 새로운 기능 중 몇 가지를 함께 살펴보겠습니다
먼저 새로운 다국어 키보드에서는 언어를 수동으로 전환하지 않아도 다른 언어를 입력할 수 있습니다
한국어와 영어를 모두 구사한다면 iOS 18에 도입될 고유의 멀티스크립트 입력 경험을 사용할 수 있습니다
기존에 있던 많은 기능이 더 많은 언어를 지원하게 됩니다 라이브 텍스트의 경우에도 이제 아랍어를 지원합니다 또한 배경화면과 시계 페이스의 숫자를 사용자 지정할 때 사용 가능한 10개의 인도어 스크립트도 추가됩니다 끝으로 전할 소식은 새로운 M4 iPad Pro용 아랍어 Magic Keyboard의 기능 키 열이 새로 디자인되어 음량 및 밝기 조절 키가 이제 정확히 하드웨어와 소프트웨어 사이에 역방향으로 배치됩니다
이러한 예시들은 Apple에서 하드웨어와 소프트웨어를 혼합해 하나의 원활한 경험을 만드는 방법 중 일부입니다 여러분이 곧 이 멋진 최신 기능을 사용해 보실 수 있기를 바랍니다 이제 뛰어난 다국어 지원 앱을 제작하는 방법을 살펴보겠습니다 오늘은 입력, 디스플레이 현지화라는 세 가지 섹션으로 이야기를 진행하겠습니다 먼저 입력에 대해 알아보며 다국어 여정을 시작해 보죠 이 여정을 함께할 세 명의 친구가 있습니다 모두 다른 지역 출신이고 구사하는 언어도 다릅니다 이 친구들의 도움을 받아 흔히 발생하는 다국어 시나리오를 시각적으로 확인해 보겠습니다 동쪽에서 서쪽으로 이동하려 합니다 입력에 대해 말하기 위해 April의 하루를 살펴보죠 April은 싱가포르에 거주하며 영어와 중국어를 구사합니다 친한 친구인 Farah와 영어로 대화를 나누며
파트너와 중국어로 소통합니다
April이 각각의 대화에 입장할 때 키보드는 April이 대화에서 사용하는 언어를 기억하고 있습니다 앱에서 어떻게 이 기능을 구현하는지 보여 드리겠습니다 아주 간단합니다 UIResponder의 메서드 textInputContextIdentifier를 오버라이드하여 고유한 문자열 ID를 반환하면 됩니다 April은 손글씨 키보드로 중국어를 입력할 때 키보드를 위로 늘려서 더 편하게 사용하는 경우가 많습니다 이렇게 하면 메시지 앱은 UI를 위로 올려 공간을 확보합니다
두 가지 방법으로 구현할 수 있습니다 먼저 키보드 바로 위에 뷰를 배치해야 한다면 키보드 위에 뷰를 고정하는 inputAccessoryView가 적절합니다 하드웨어 키보드를 사용하여 입력하는 경우에도 화면 하단에 뷰가 고정되도록 처리해 줍니다 또 다른 방법은 keyboardLayoutGuide입니다 뷰가 키보드를 기준으로 배치되도록 맞춤화할 때 편리합니다 또한 중국어나 일본어 같은 언어를 입력할 때 키보드는 표시된 텍스트를 사용합니다 표시된 텍스트가 무엇이냐고요? 보여드리죠 표시된 텍스트는 제안을 선택하기 전의 임시 텍스트이며 밑줄이 그어져 있습니다 제안을 선택하면 표시된 텍스트는 사라집니다
이제 버그를 하나 보여 드리죠 앱에서 키를 입력할 때마다 텍스트를 수정하여 입력을 방해하는 버그입니다 왜 그럴까요? 입력과 동시에 자동 완성하기 위해서인 경우가 많습니다 그렇다면 유용한 인라인 자동 완성을 제공하면서 April이 여전히 중국어를 입력할 수 있도록 구현해 보죠 핵심은 텍스트를 수정하기 전에 표시된 텍스트가 있는 것은 아닌지 확인하는 겁니다 markedTextRange가 결과로 empty를 반환하는 경우 안전하게 텍스트를 수정하여 인라인 자동 완성을 표시할 수 있습니다 표시된 텍스트가 있는 동안에도 해당 텍스트를 기반으로 검색해 다른 곳에 제안을 표시할 수 있습니다 예를 들어 테이블 뷰에서 말이죠 사실 Spotlight가 바로 이렇게 동작하죠 보시는 대로 입력하는 동안 상단의 제안이 업데이트되고 제가 후보를 확인하면 Spotlight가 인라인 텍스트를 수정합니다 고마워요, April 이제 Raj의 예를 살펴보며 멋진 검색 경험을 제작해 보겠습니다
Raj는 인도에 거주하며 힌디어와 영어를 사용합니다 힌디어로 검색하며 가끔 원하는 내용을 찾지 못할 때가 있습니다 문제의 원인을 찾아보고 해결 방법을 알아보겠습니다
각 언어는 각자의 규칙대로 완전히 다른 철자인지 서로 연관된 철자인지 판별합니다
영어에서 소문자 a로 apple을 검색하면 대문자 A의 Apple도 검색할 것으로 예상합니다 독일어 등 다른 언어에도 비슷한 규칙이 있습니다 Raj의 경우 연락처에 저장한 이름에 대응되지 않는 다른 방식의 철자법으로 이름을 입력했습니다 다행히 코드 한 줄만 수정하면 해결할 수 있으며 localizedStandardRange를 사용합니다 localizedStandardRange는 아시겠지만 지역별 규칙을 적용해서 검색하는 표준 방법입니다 올해는 이 API의 작동 방식도 크게 개선되어 이제 더 다양한 스크립트에서 여러 철자법 사이에 대응하도록 지원하며 스크립트 간에 숫자를 대응하는 기능도 강화되었습니다 localizedStandardRange 및 iOS 18의 새로운 개선사항을 통해 Raj는 이제 선호하는 철자법으로도 연락처를 쉽게 찾을 수 있습니다
마지막으로 Raj가 가끔 만나는 문제가 있습니다 검색 필드에 입력할 때 발생하는 문제인데요. 같이 살펴보겠습니다
어떤 앱에서는 Raj가 힌디어를 입력하면 텍스트가 깨져서 표시됩니다
앱이 입력된 텍스트의 일부분만 강조하여 표시하기 때문이죠
힌디어를 비롯한 많은 언어에서 문자에는 모음과 여러 기호가 붙습니다 예시를 위해 단어 하나를 입력하겠습니다 क्षितिज(kshitij) 수평선이라는 뜻으로 하나씩 입력하죠 입력하면서 어떻게 바뀌는지 보세요
보시다시피 힌디어에서는 문자 입력 시 항상 오른쪽에 삽입되는 것은 아니며 기존 문자를 수정할 수도 있습니다
기본 문자와 볼드체 문자는 사실상 다른 폰트이며 문자는 다른 폰트의 기호와 연결될 수 없으므로 텍스트가 분리되어 표시되는 겁니다 하지만 다행히도 색상을 통해 텍스트의 강조된 부분을 표시할 수 있습니다 attributedString에 색상 속성을 추가하는 코드입니다 이 주제를 설명하는 김에 이탤릭체에 대해서도 첨언하겠습니다 10개 언어로 ‘안녕하세요’를 표현해 봤습니다 전부 이탤릭체로 만들어 보겠습니다 10개 중 3개만 변경되었죠 나머지 언어에는 이탤릭체 개념이 없기 때문에 이탤릭체를 적용해도 시각적으로 변하지 않습니다 이탤릭체를 사용할 때는 주의하세요 번역되면 이탤릭체가 구분되지 않을 수 있으니까요
이제 볼드체 대신 색상으로 강조하니 Raj는 검색 결과를 읽을 수 있고 여전히 강조되므로 검색 결과의 어느 부분이 입력한 텍스트와 일치하는지 확인할 수 있습니다 여기까지 입력에 대한 설명이었습니다 Raj와 April에게 감사를 전합니다 이제 텍스트 표시 방식에 대해 이야기하죠 표시 방법에 대해서는 Ismat의 입장에서 살펴보겠습니다
Ismat은 미국에 거주하며 영어와 우르두어를 사용합니다
우르두어 텍스트는 대부분의 앱에서 완벽하게 표시되지만 가끔 어떤 앱에서는 텍스트가 너무 뭉개져 읽을 수가 없는 경우가 있죠 이 단어는 نستعلیق(Nastālīq)인데요 우르두어 스크립트의 서체 이름으로 왼쪽은 바르게 렌더링된 모습이고 오른쪽은 그렇지 않습니다 해결 방법은 간단하며 TextKit 2를 사용하면 됩니다 Apple의 차세대 텍스트 엔진으로 모든 스크립트를 올바르게 렌더링하죠 다행히도 SwiftUI나 AppKit 또는 UIKit에서 레이블이나 텍스트 뷰에는 이미 해당 엔진이 적용되어 있습니다
Ismat이 지난 날을 떠올리며 일기를 되돌아보고 있습니다
여기서 바람직한 점은 일기 앱이 영어로 실행되고 있음에도 TextKit 2 덕분에 우르두어 텍스트가 아름답게 렌더링된다는 사실입니다 한편, 일기 앱을 비롯한 대부분의 앱에서는 우르두어 텍스트가 제대로 출력되지만 일부 앱에서는 행 간격이 너무 좁아 읽기 어려울 때가 있습니다 일기 앱은 우르두어를 제대로 처리하지만 우르두어 전용 코드는 한 줄도 없습니다 다른 많은 앱과 마찬가지로 텍스트 스타일을 사용하기 때문입니다 이 기능을 사용하면 앱의 설정 언어뿐만 아니라 Ismat의 경우처럼 사용자의 설정된 모든 언어를 고려하여 모든 앱에서 선호하는 모든 언어의 텍스트를 올바르게 렌더링합니다 텍스트 스타일은 쉽게 사용할 수 있습니다 SwiftUI, UIKit, AppKit에서 텍스트 스타일을 초기화하는 다양한 방법입니다 또한 clipsToBounds는 레이블 또는 텍스트 뷰에서 기본값 false를 유지해야 합니다 뷰 경계 외부에서도 텍스트가 렌더링되어야 하는 앱이 많기 때문이죠 그렇지 않으면 읽기 어려울 수 있으니까요
특정 언어로 콘텐츠를 표시하면서 해당 언어에 맞는 최적의 조판 동작을 설정하고 싶을 때가 있을 겁니다 이러한 경우에는 typesettingLanguage를 지정하면 됩니다
왼쪽은 선호 언어를 모두 고려하는 기본 설정으로 출력한 것으로 Ismat의 경우 우르두어까지 포함됩니다 같은 뷰에서 typesettingLanguage를 영어로 설정해 출력한 결과가 오른쪽입니다 더 좁은 행 간격으로 텍스트를 출력할 수 있죠 마지막으로 April, Raj, Ismat 모두 이름을 바르게 표시하는 것이 얼마나 중요한지 강조하고자 합니다 formatted API를 사용하여 모든 언어와 스크립트의 이름을 올바르게 표시할 수 있습니다 앱의 설정 언어와 상관없이 말이죠 예를 들어 이름만 표시하는 건 중국어나 일본어 같은 언어에서는 적절하지 않습니다 이 경우 포매터의 짧은 스타일을 사용하여 적절한 경우에만 이름을 표시할 수 있습니다 모노그램에서는 축약 스타일을 사용하죠
April, Raj, Ismat과는 이제 작별을 고하고 앱을 현지화할 때 사용하는 여러 도구가 어떻게 개선되었는지 살펴보도록 하겠습니다
먼저 String Catalog입니다 String Catalog는 Xcode에서 현지화할 때의 핵심 기능으로 프로젝트의 번역을 관리하는 프로세스를 간소화하기 위해 코드와 문자열을 동기화하고 강력한 편집 도구를 제공합니다 스트링 카탈로그의 개선점을 살펴보죠
이제 스트링 카탈로그에서는 형식 지정자 불일치 등 흔히 발생하는 검증 문제를 감지해 클릭 한 번으로 수정하는 기능을 제공합니다
다음으로 특정 문자열을 ‘번역 안함’으로 표시하여 번역가에게 아직 콘텐츠의 마무리 작업을 진행 중이라고 쉽게 알려줄 수 있습니다
마지막으로 이제 특정 문자열의 코드와 카탈로그를 손쉽게 번갈아 가며 확인할 수 있습니다 스트링 카탈로그의 이러한 모든 개선사항이 개발 및 현지화 작업 흐름에 도움이 되기를 바랍니다 이제 앱의 각 문자열을 더 개인적이고 포용적으로 수정하여 더 멋지게 표현해 보겠습니다
강력한 자동 문법 일치 엔진 덕분에 앱은 언어 및 지역 설정에서 지정한 호칭에 따라 사용자를 표시할 수 있습니다
또한 사용자가 설정한 인칭 대명사로 표시할 수도 있습니다 마지막으로 앱의 모든 텍스트가 문법적으로 올바르게 표시될 뿐만 아니라 그러한 작업을 위해 텍스트별로 수십 가지 다양한 버전의 문자열을 입력해 둘 필요가 없습니다 모두 문법 엔진 덕분입니다 올해부터 문법 엔진이 2개 언어를 추가로 지원합니다 첫 번째는 힌디어입니다 힌디어로 기기를 사용한다면 이제 언어 및 지역 설정에서 원하는 호칭을 지정하고 어떻게 표시될지 선택할 수 있습니다
문법 엔진은 한국어에도 적용될 예정이며, 앞으로는 후속 단어에 따라 조사가 바르게 삽입될 것입니다 이제 앱이 한국어, 독일어, 영어 스페인어, 프랑스어, 이탈리아어 포르투갈어, 힌디어를 지원한다면 자동 문법 일치의 강력한 성능을 활용할 수 있습니다
이제 숫자에 대해 살펴보겠습니다 영어에서는 아라비아 숫자를 사용하며 다른 수십 개 언어에서도 역시 아라비아 숫자를 사용합니다 하지만 아라비아 숫자 외에도 세상은 다양한 숫자 시스템을 사용합니다 두 가지 이상의 시스템을 지원하는 언어의 경우 사용자가 언어 및 지역 설정에서 원하는 시스템을 선택할 수 있습니다 바람직한 소식은 포매터를 사용하면 모든 지역별 규칙이 숫자에 자동으로 적용된다는 겁니다 포매터를 사용하지 않고 숫자 형식을 지정하는 방법을 보여 드리죠 ‘10일간의 일기예보’라는 날씨 앱의 텍스트입니다 일반적으로 이를 현지화된 문자열로 나타내죠
두 가지 방법으로 현지화할 수 있습니다 먼저 보간 기능으로 코드에 숫자의 형식을 지정하는 방식입니다 Text 내부에 있으므로 numberOfDays가 현재 지역에 맞게 자동으로 형식이 지정됩니다 이 방법은 런타임에 숫자가 무엇인지 결정되고 모든 언어가 이 문자열에서 숫자를 사용한다면 제대로 작동합니다
올해에는 문자열 안에서 직접 숫자 형식을 지정할 수 있는 두 번째 방법이 추가됩니다 이 방법은 코드 내에서 형식을 지정할 때와 같은 모든 상황에 사용할 수 있습니다 하지만 이 방법의 가장 큰 이점은 현지화된 문자열 내에서 코드 없이 손쉽게 숫자 형식을 지정할 수 있다는 겁니다
이 첫 번째 예시에서는 이 방법으로 ‘10일간의 일기예보’ 문자열을 현지화할 수 있습니다 이 예시에서는 원본 영어 문자열과 번역된 힌디어 문자열에서 formatNumber를 사용하여 언어 및 지역 설정에 지정된 숫자 설정에 따라 런타임에 올바른 숫자 시스템으로 숫자를 표시합니다
숫자 시스템 외에도 소수점과 같은 다른 숫자 형식도 처리할 수 있습니다 즉 스페인어로 설정해도 하나의 문자열을 스페인어와 영어에 모두 사용할 수 있습니다
다양한 현지화를 지원하는 앱의 경우 사용자가 언어 및 지역 설정에 둘 이상의 언어를 지정한 경우 자동으로 언어 설정이 표시되며 기기 전체 언어 설정과 독립적으로 사용자가 앱별 언어를 설정할 수 있습니다 이 기능은 다양한 언어의 다양한 앱을 사용하는 경우가 많은 다국어 사용자에게 매우 널리 사용됩니다 사용자가 언어 및 지역 설정에서 선호하는 언어를 둘 이상 지정하지 않더라도 앱에서 언어 옵션을 항상 표시하고 싶다면 InfoPlist에서 UIPrefersShowingLanguageSettings를 활성화하면 됩니다
또한 필요하다면 앱에서 설정으로 넘어가는 버튼 같은 어포던스를 추가할 수도 있습니다 마지막으로 SF Symbols가 현지화할 때 매우 중요한 도구라는 점을 강조합니다 이러한 기호를 다양한 언어와 스크립트로 현지화하기 때문이죠 Apple 앱에서 흔히 사용되는 모든 기호는 SF Symbols를 사용합니다 예를 들어 포맷 제어 기능을 표시하는 textformat에 사용됩니다 서명처럼 불규칙적인 기호조차도 각 언어에서 자연스럽게 표시되도록 맞춤화됩니다 SF Symbols는 오른쪽에서 왼쪽으로 쓰는 언어나 다양한 숫자 시스템을 지원하니까요 따라서 앱에 사용할 기호를 찾고자 한다면 먼저 SF Symbols의 방대한 라이브러리를 살펴보시기 바랍니다
정리하자면 오늘날의 다국어 세상에서 사람들은 앱에서 선호하는 언어를 사용하고 싶어합니다 이러한 사용자들에게 멋진 경험을 제공하려면 모든 언어에서 키보드 입력과 언어 표시가 잘 동작해야 합니다 또한 개발 및 현지화 작업 흐름을 크게 가속할 수 있는 String Catalog 같은 도구를 활용할 수 있습니다 여러분이 제작할 다국어 지원 앱이 기대됩니다 감사합니다, شکریہ(shukriyā) धन्यवाद(dhanyavād), 謝謝(xièxiè)
-
-
3:18 - Specify textInputContextIdentifier
override var textInputContextIdentifier: String? { uniqueID }
-
3:41 - Place a view directly above the keyboard
textView.inputAccessoryView = viewAboveKeyboard
-
4:00 - Use keyboardLayoutGuide to adapt to keyboard
view.keyboardLayoutGuide.topAnchor.constraint(equalToSystemSpacingBelow: textView.bottomAnchor, multiplier: 1.0).isActive = true
-
4:42 - Check for marked text before modifying
if textView.markedTextRange.empty { // Perform actions involving editing text }
-
5:58 - Use localizedStandardRange when searching
let range = text.localizedStandardRange(of: search)
-
7:24 - Use color differences to highlight text
attributedString[range].foregroundColor = highlightColor
-
9:39 - Text Styles
// Text Styles // SwiftUI Text("Hello, world!") // uses .body Text Style by default Text("Hello, world!").font(.title) // UIKit let label = UILabel() label.text = "Hello, world!" label.font = UIFont.preferredFont(forTextStyle: .body) // AppKit let textField = NSTextField(labelWithString: "Hello, world!") textField.font = NSFont.preferredFont(forTextStyle: .body) // Keep clipsToBounds off clipsToBounds = false
-
10:03 - Typesetting language
// Typesetting language // SwiftUI Text(verbatim: "Hello, world!").typesettingLanguage(.init(languageCode: .english)) // UIKit let label = UILabel() label.text = "Hello, world!" label.traitOverrides.typesettingLanguage = Locale.Language(languageCode: .english)
-
10:29 - Formatting names
// Formatting names let nameComponents = PersonNameComponents (givenName: "瑗珺", familyName: "汪", nickname: "珺珺") // Short Name (respects settings like “Prefer Nicknames”) let shortName = nameComponents.formatted(.name(style: .short)) // 珺珺 // Abbreviated Name (can be used for monograms) let monogram = nameComponents.formatted(.name(style: .abbreviated)) // 汪
-
12:20 - Examples of personalizing text
"^[Nuestro %@](inflect: true) está ^[hecho](agreeWithArgument: 1) de %@." "अगर आप पहुँच नहीं ^[पाते हैं](inflect: true)" "예: ‘^[%@을](inflect: true) 켤 때’"
-
13:43 - Format numbers using Text
Text("\(numberOfDays)-day forecast")
-
14:21 - Format numbers using AttributedString
AttributedString(localized: "10-day forecast") AttributedString(localized: "0.5× zoom")
-
15:23 - Launch to your app’s settings
// Launch to your app’s settings if let url = URL(string: UIApplication.openSettingsURLString) { await UIApplication.shared.open(url) }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.