其它相关内容请见虚拟现实(VR)/增强现实(AR)&visionOS开发学习笔记
苹果的产品遍布一百多个国家,使用几十种语言和方言发行应用,但通常我们只能创建一个版本的应用,所以就需要对不同市场进行适配。这不仅仅是翻译,还有用户界面中元素的排列、数字的格式等等。这一客制化的过程称为本地化。在SwiftUI中,大多数本地化会自动完成。例如,SwiftUI视图的内容采用靠前(leading)和靠后(trailing)约束来根据文字顺序(从左到右或从右到左读)的不同来表示左和右,日期和充其量单位等值会自动根据所在地进行格式化(参见示例4-32)。但文本还是需要我们来翻译。为此Xcode提供了字符串名录(String Catalogs)。
String Catalogs
字符串名录是由Xcode所提供了一个工具,借助它我们可以进行文本翻译、适配目标语言。系统会跟踪代码中的本地化文本,创建一个文件供我们编辑和发送给专业的翻译人员。该文件的创建方式和其它文件一样通过File菜单,选项们于Resource版块下。
图20-1:字符串名录文件
文件可使用任意名称,添加后的效果如下:
图20-2:在项目中添加字符串名录
每次运行或构建程序时,系统会跟踪视图、更新该文件的内容。我们使用一个简单的视图来进行测试。
例20-1:测试字符串名录:
1 2 3 4 5 6 7 8 9 10 11 |
import SwiftUI struct ContentView: View { var body: some View { VStack { Text("Hello World!") .padding() Spacer() } } } |
这一视图包含一个Text视图,文本为"Hello World!"
。在运行或构建应用时(Command + B),这段文字会进入字符串名录文件中,如下图所示。
图20-3:更新后的字符串名录文件
选中字符串名录文件时,Xcode会显示一个可编辑其内容的界面。该界面左侧面板显示可用语言,右侧提供了各种语言的翻译和适配信息。
当前创建的文件仅使用了默认语言(本例中为英语)。点击左下角的+按钮添加一种语言。点击该按钮时,会弹出一个可添加的语言列表。
图20-4:语言
添加好语言后,可以点击对应的语言为各段文本添加翻译。下例中我们添加了西班牙语及其翻译文本。
图20-5:西班牙语翻译
✍️跟我一起做:创建一个多平台项目。按照例20-1中的代码更新ContentView视图。打开File菜单,创建一个字符串名录文件(图20-1)。在模拟器中运行应用或按下Command + B构建应用。打开字符串名录文件。应该会在列表中看到”Hello World!”文本。使用该项目测试本章后续的示例。
本地化已就绪。此时在说西语的国家打开应用,Text视图中显示的文本就是”Hola Mundo!”。这在用户的设备上自动完成,但若要在Xcode上测试就需要修改schema或配置预览。通过更改schema,可以在模拟器或设备上测试本地化。点击Xcode工具栏中的项目名称,选择Edit Scheme…选项即可编辑schema,如下图所示。
图20-6:Schema菜单
这会打开一个包含所有项目配置选项的窗口。修改语言必须点击Run打开Options面板,通过App Language选项选取语言(图20-7,1号标注)。
图20-7:应用语言选项
代码请见:GitHub仓库
在配置成希望显示的语言后,预览、模拟器和设备都会使用这一配置运行应用。如果只希望在预览界面测试本地化,可以仅实现如下的环境属性。
- layoutDirection:本属性决定文本的书写朝向。它是一个LayoutDirection枚举,值有leftToRight和rightToLeft。
- locale:本属性决定视图所使用的位置。它是一个Locales结构体。
要修改这些属性,必须对预览应用enviroment()修饰符,和第5章中的操作一样(例5-93)。例如,我们可以创建两个预览,一个使用默认语言,另一个使用西班牙语。
示例20-2:选取预览的语言
1 2 3 4 5 6 7 |
#Preview { ContentView() } #Preview { ContentView() .environment(\.locale, Locale(identifier: "es")) } |
此时预览界面中会显示两个预览,一个使用英语文本(“Hello World!”),另一个使用西语文本(“Hola Mundo!”)。
图20-8:多语言预览
Xcode所提供的编辑字符串名录的界面仅适用开发者。如果与第三方翻译人员合作,可以导出文件,在拿回翻译文件后再进行导入。这一选项位于Product菜单中(图20-9,一号标注)。
图20-9:导出/导入选项
在将本地化文件发送给翻译人员时,推荐包含注释协助他们实现最精准的翻译。为此,Text视图包含了如下的初始化函数:
- Text(String, comment: StaticString?):这一初始化函数创建一个Text视图,通过第一个参数指定其文本,通过comment参数指定注释。StatictString结构体是设计用于表示在应用编译后不再发生变化的文本。
我们可以使用这个初始化函数在界面中创建所有的Text视图。下例中,我们对Text视图添加注释,以便翻译知道这段文本的作用。
示例20-3:添加供翻译查看的注释
1 2 3 4 5 6 7 8 9 |
struct ContentView: View { var body: some View { VStack { Text("Hello World!", comment: "This is a welcome message") .padding() Spacer() } } } |
系统跟踪视图查找可包含在字符串名录中的本地化文本。如果文本存储在属性中,或是由外部进程生成,就必须将其声明为可本地化,否则系统找不到。为此String结构体包含有如下的初始化函数。
- String(localized: String):此初始化函数创建一个带本地化字符串的String结构体。
通过这个初始化函数,我们可以本地化所有需要对用户显示的文本。例如,我们可以在视图中添加一个按钮,在点击后修改某个Text视图中的文本,然后同时本地化原始文本和按钮所赋值的文本。
注意当前在预览窗口中仅有按钮的文本会本地化。
示例20-4:本杝化字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct ContentView: View { @State private var mytext = String(localized: "Hello World!") var body: some View { VStack { Text(mytext) .padding() Button("Change Text") { mytext = String(localized: "Goodbye World!") } Spacer() } } } |
在应用构建时,系统会跟踪社图,查找Button视图中的文本,然后检查代码找到更多的本地化文本。本例中我们声明了两个本地化String结构体,一个设置Text视图的初始文本,另一个赋值给点击按钮后的社图。此时字符串名录包含三段翻译文本。
图20-10:待翻译的本地化文本
如果通过某个进程接收到常规字符串,我们可以通过定义类型为LocalizedStringResource的属性来告知系统该字符串是可本地化的。这个结构体包含指定该文本的初始化函数,还有一个可选注释参数。
- LocalizedStringResource(String, comment: StaticString?):这一初始化函数创建一个结构体,表示从其它程序接收到的可本地化字符串。
例如我们在希望接收到的常规化字符串可进行本地化时使用这一结构体。
示例20-5:值的本地化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
struct ContentView: View { var body: some View { VStack { MyView(mytext: "Hello World!") Spacer() } } } struct MyView: View { let mytext: LocalizedStringResource var body: some View { Text(mytext) .padding() } } |
除了翻译外,字符串名录还可用于指定文本的单复数。如果文本中包含该值,系统会自动选择正确的文本显示给用户。例如,下例中包含一个存储整数的@State属性,以及一个在屏幕上进行显示的Text视图。每次点击按钮时,值会递增1。
示例20-6:指定文本的单数和复数版本
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct ContentView: View { @State private var counter = 1 var body: some View { VStack { Text("\(counter) Item") .padding() Button("Add Unit") { counter += 1 } Spacer() } } } |
在Text视图中,和counter属性值一同显示的还有单词”Item”。问题是在值在于1时文本应显示为”Items”。我们可以打开字符串名录为该文本设置两个版本,按住Control键点击该单词。此时会打开一个菜单,包含指定设备设置不同版本以及设置单复数的选项。
图20-11:版本菜单
选择Vary by Plural选项,系统会为单复数创建两个新字段。
图20-12:单数和复数版本
本例中,单数指定为”Item”,复数版本指定为”Items”。
此时会根据counter属性的值向用户展示不同版本的文本。
图20-13:按属性值展示文本