大多数浏览器和
Developer App 均支持流媒体播放。
-
构建全球化 App:本地化的示例
了解如何在遍布世界各地的设备上运行您的 App,并让不管使用何种语言的所有用户都能获得出色的体验。我们将探索如何在为不同受众构建 App 时,利用 Apple 的 API 来提供稳固的基础;此外,我们还将根据我们自己的经验,分享示例、挑战以及最佳实践。
资源
- Expanding Your App to New Markets
- Internationalization and Localization Guide
- Localization
- Localizing package resources
相关视频
WWDC23
WWDC22
WWDC21
WWDC20
-
下载
Andreas: 大家好 欢迎来到全球开发者大会 我是来自 Apple 本地化团队的 Andreas 今天我想和您分享一些 关于如何创建高质量的 本地化 App 的示例
国际化意味着让您的 App 在世界各地的设备上运行 如果本地化做得好 所有人都能享受到同样棒的 体验和功用 不管他们说的是什么语言 使用 Apple 提供的 API 您的 App 的大多数部分 都会易于国际化 开箱即用 在本期演讲中 您将从我们的经验中 学习如何让 Apple App 吸引不同的受众 包括存在的一些挑战 和我们该如何解决它们 我将从声明和加载本地化文本开始 字符串中很容易包含 格式化的日期 时间等 我将特别强调一些选项 并将研究一个复杂的示例 您的 Swift 软件包 可能也包括本地化文本 您将会了解到本地化工作流程的改进 最后 我将谈谈 SwiftUI 的 布局和新功能 在 Apple 我们会确保我们的 App 能为世界各地的用户提供卓越的体验 天气 App 就是一个例子 每天都有数百万用户打开它 查看天气预报 无论他们身在何处 他们眼中的 App 都是这样的 注意 UI 中的所有内容是如何 根据他们的首选项进行调整的 我们将对当前天气状况的描述本地化 并格式化数字 UI 也会根据语言是从左到右的 还是从右到左的进行适当调整 让我们从翻译开始仔细看看某个 自定义的内容 这个视图用英语写着 “风让体感更凉爽”(Wind is making it feel cooler.) 这是它在其他语言中的样子 为了正确地运行它们 我们所要做的就是使用 (本地化的)String 声明字符串 Xcode 会在导出本地化时发现它 然后我们就可以将结果 发送给我们的翻译人员 我将使用 Mac 上的 Mail App 来做到这一点 既然我们说到这儿了 我想给您看样东西 如果我打开电子邮件的快捷菜单 我可以把它移动到一个 名为 Archive 的特殊文件夹 它位于我的侧边栏中 注意这两个单词在英语中 都是 Archive 但是其他语言 如西班牙语 关于操作和文件夹名称 有不同的单词 即使英语单词是相同的 但是当它们出现在不同的语境中时 其他语言可能会使用不同的单词 在这种情况下 应该在代码中使用两个字符串 为此 今年我们给字符串初始化器 添加了新的 API 它现在接受了一个默认值 我们可以将其用于英语字符串 然后 我们要修改本地化字符串的键 使翻译人员清楚地了解区别 通过这种方式用英语运行 App 时 会显示相同的单词 而西班牙语翻译可以提供不同的单词 去年的演讲 “Streamline your localized strings” 帮助您理解了管理字符串的基本知识 并进一步介绍了本地化过程 我希望您从这个例子中学到 有时候同一个英文单词 甚至是一个完整的句子 会在 UI 里不同的环境中显示 在这些情况下 请确保在代码中 使用两个不同的字符串 天气不仅仅与 App 有关 它也能很好地集成到系统中 在这里 我们能看到一个用户活动 建议打开 App 来检查当前位置的天气 让我们看看如何实现它 可以像这样使用字符串插入(String Interpolation) 插入任何位置名称来声明 加载字符串 这个名字可以是一个城市 也可以是当前位置的一个术语 这个结果在英语中效果很好 分别是 “Show weather in Cupertino” 和 “Show weather in my location” 但是 在其他语言中 我们可能会遇到语法问题 例如 在德语中 介词可以用于城市名称前 但插入表示当前位置的词前时 就错误了 我们需要一个不同的翻译来代替 解决方案很简单 用两个不同的字符串 在第一个字符串中 插入城市名称没有问题 对于当前位 我们要使用另一个字符串 这可以确保翻译人员 能够使用正确的 语言语法 这些在英语和德语中都很好用 我做这个例子是为了向您展示 插入一个变量 会对整个句子产生影响 在其他语言中 连接字符串 可能会产生令人惊讶的结果 它们可能需要改变语法 或者可能在大写方面有问题 但要在编写代码之前 想到这一点很困难 让会说这门语言的人测试 App 是工作流程的重要部分 当您试图以编程方式构造字符串时 请记住这一点
现在我们已经很好地理解了 字符串是如何在代码中被声明的 让我们来聊一聊它们的注释 下面是我们上一个例子中的字符串 并附有适当的注释 注释对翻译来说非常非常重要 您应该确保为它们 能提供翻译所需的上下文 使译文与您声明 字符串时的意图保持一致 一个好的注释解释了字符串 显示在哪个界面元素中 类似于标签或按钮 它还解释了 UI 元素的上下文 以及它在屏幕上显示的位置 它可以是一个段落头 一个快捷菜单 或者一个用户活动 如果字符串包含变量 请确保在运行时解释它们的值 如我们在例子中看到的 这对于匹配句子的语法非常重要 记住 翻译在翻译内容时 可能不会看到运行时的 App 但是通过这些技巧 您应该能够在字符串的声明 和翻译 它在您的 App 中 扮演的角色之间建立一个共识 现在 您可能从来没有想过 但天气 App 实际上 并不能控制天气 相反 数据是从服务器下载下来的 它可能位于世界上的任何地方 甚至可能不知道用什么语言发送内容 当内容被下载到用户的设备时 它应该一直以用户 更愿意使用的语言呈现 只本地化应用的某些部分 可能会让人非常困惑 在这里 天气 App 显示了 一个恶劣天气警报 它是从服务器加载来的 这看起来真的很严重 如果它没有翻译成我的语言 我之后可能会遇到麻烦 让我们看看可以做些什么 来确保用户能 持续读取远程内容
您的服务器可以向 App 发送支持的语言列表 这应该是一个语言 ID 的阵列 设备有关于用户喜欢哪种语言的 所有数据 这样您就不必自己检查比较它们 您可以通过调用 “Bundle.preferredLocalizations” 来利用 Apple 的框架 它会帮您匹配 它会返回一个候选语言的数组 根据它们与用户的语言选择的 匹配程度排序 第一个通常是最合适的 所以您要用这个 然后 应将该语言用于 对服务器的任何后续请求 它会用它生成一个回应 其内容是用户能够理解的语言 使用这种技术 您可以确保来自服务器的字符串 为更新 UI 和向用户显示警报 做好了准备 因此 为了使用户在显示远程内容时 避免困惑 请下载可用的语言 将其与用户的语言偏好进行匹配 并在加载面向用户内容的任何请求时 使用该结果 但现在让我们再看看更好的天气 无论晴雨 天气 App 的数据都非常丰富 它的许多方面都包含数字和计数 让我们关注其中一个 降水(Precipitation) 下面写着 “最近 6 小时内会有 0 毫米。” 让我们假设您想要构建类似的内容 但这里改为 “ 1 小时” 这就是在代码中声明字符串的方式 在英语中 如果小时数大于 1 您就需要使用复数形式 1 小时是 hour 但 2 小时是 hours 在乌克兰语中要使用另一种变体 其规则更加复杂 您不会希望在代码中实现这种逻辑 这就是为什么要利用 Apple 框架 您所要做的 就是在代码中声明字符串 并提供一个 stringsdict 文件 该文件会对复数规则进行编码 另一个选择是使用 自动语法协议(Automatic Grammar Agreement) 您可以在去年的演讲 “Streamline your localized strings” 中 了解更多关于这两种技术的内容 尽管这很简单 但您不应该总是将复数规则 应用于所有字符串 例如 如果您的句子不要计数 也不包括数字 您就不应该使用复数规则 在这里 “Remove this city from your favorites” 不需要该规则 因为其中没有数字 而且同样适用于多个城市 但如果字符串确实包含一个数字 您应该考虑使用复数变形 前面示例中的字符串 计算了未来几个小时的降雨量 我们刚刚学习了让它依据 大于 1 的数字改进是多么容易 但是 如果句子中有一个单位 比如持续时间 时间或百分比 您应该考虑使用格式化器 所以 现在让我们来聊聊格式化器(Formatter)吧 气候会在这个视图中 以百分比显示当前湿度 要在 SwiftUI 中实现这一点 只需要一行代码 您只需在 Text() 中填入您需要的值 并指定您希望如何格式化这个数字 等效的 Swift 代码也很简单 您只需要在值上调用 .formatted
这就是您需要做的全部工作 而格式化器会处理其他所有事情 它不仅会将百分号 放在数字的前面或后面 并添加空格 它还会适应用户偏好的编号系统 这是阿拉伯语和印地语用户所期望的 但这仅仅是可以格式化的 数据类型的开始 几乎所有的东西都有格式化器 我建议您再看一次讲座 “Formatters: Make data human-friendly”
正如我们所看到的 天气并不总是晴朗的 有些日子会下雨 当然 天气 App 也不能缺少这个亮点 降雨(Rainfall) 一栏写着 “50 mm expected in next 24 hours”(预计未来 24 小时内会有 50 毫米。) 我真的很高兴这不是我的 所在地的情况 在英语中 情况很简单 我们会说 “50 millimeters expected in next 24 hours.” 但是在西班牙语中 事情要复杂得多 我们需要依据降水量是单数或复数 来改变翻译 我们可以通过结合格式化器 和复数规则来解决这个问题 字符串 2mm 是由格式化器生成的 它被嵌入到了一个在西班牙语中 需要改为复数形式的句子中 好的 让我们看看 如何在代码中做到这一点 我们首先要声明一个 带有一个参数 关于降水量的函数 单位是毫米 它可能是从服务器上下载的 首先 我们要向系统请求一个 UnitLength 它会对用户的配置进行编码 并为要显示降雨的情况 选择正确的长度 如果用户没有将其系统 配置为使用公制 那么可以很容易地将 Measurement 类型转换为偏好单位
接下来 格式化 API 会让我们能够在一行代码中为值 生成格式化字符串 偏好单位已经有了我们想要显示的 降雨信息 所以格式化时 我们要 将用法设置为 asProvided 如果降雨量超过 1 毫米或 1 英寸 我们希望使用复数形式 我们要把这个值转换成一个整数 这样我们就可以检查它了 接下来 我们要加载一个 带有给定键的本地化字符串 并提供一个默认值 在这里 我们要用字符串插值 来包含 integerValue 格式化值和数字 24 这个数字是在代码中定义的 因为它永远是 24 小时 使用字符串插值能自动确保 使用正确的编号系统 该键在 stringsdict 文件中被声明 让我们来看看 stringsdict 以我们刚刚 在代码中使用的键开始 在英语中 我们不需要为复数 改变字符串的形式 所以我们可以用 Other 这一类别来表示它 第一个参数会定义 在运行时选择哪个类别 记住 它是整数值 参数 2 和 3 出现在格式化字符串中 这定义了句子在运行时的样子 西班牙语的 stringsdict 具有相同的结构 只是我们同时提供了 单数和复数的翻译
我们现在已经用代码格式化了数据 并将其放入一个句子中 stringsdict 文件包含复数规则 这样西班牙语翻译 使用的就是正确的语法 有时候 提供一个适合所有语言的 完全本地化的 UI 是很有挑战性的 同样 连接字符串在英语中可以运作 但在其他语言中可能会产生 令人惊讶的结果 这可能需要一些全面的代码来完成 但现在您知道了该如何 使它能适合所有用户 有时候您的字符串会处在依赖关系中 或者在 App 使用的模块中 或者您也可以使用 Swift 软件包将自己的代码 分发给其他开发人员 让我们看看本地化的新内容 要定义一个 Swift 软件包 您需要通过使用 Swift 本身来声明结构和构建配置 如果您有面向用户的内容 您可以使用参数 default Localization 来声明 内容使用英语 作为主要语言 这类似于指定 App 项目的 开发语言 Xcode 现在会读取这个参数 并识别出 您对提供本地化体验感兴趣 因此 它将向 Product 菜单添加 Export Localizations 选项 您可能已习惯于在您的主 App 中 使用这个功能 现在它也适用于 Swift 软件包 如果您点击 Export 那么Xcode就会 读取您的代码并提取所有的字符串 它们被放在 .xcloc 文件中 发送给翻译人员 要将本地化后的内容导入到包中 需要使用 Import Localization Xcode 会将本地化后的文件 放到包中正确的文件路径里 现在 本地化一个 Swift 软件包的 工作流程和本地化您的 App 是一样的
但是记住 在 Swift 软件包中 加载一个字符串 需要指定 bundle 参数 您可以在演讲 “Swift package: resources and localization”中 了解到更多 如果您是一个以 Swift 软件包 形式发布的库的作者 您现在有了一个保持项目更新 并使本地化成为您工作流程的 常规部分的简单方法 您在您的项目中投入了 大量的精力和关注 将其本地化将为所有客户端 节省大量的时间 这一定能让它脱颖而出 让人们意识到您是在额外付出 用您的软件为他们提供最好的体验 所以去大胆地告诉他们吧 对您所支持的语言保持开放的态度 作为一名 App 开发人员 您需要特别考虑 依赖关系 不仅仅是从代码质量的角度考虑 您使用的组件应该支持 与 App 其他部分 相同的语言和高质量的翻译 在第三方代码没有本地化到 所需语言的情况下 您仍然可以创建包的本地副本 并在那里更新本地化 确保您用了 App 支持的语言 测试的它所有部分 这样就可以确保里面没有 不适合用户语言的 UI 元素 大多数情况下 翻译后的字符串 会比对应的英文字符串更长或更短 这总是会影响 App 的布局 让我们看看这对天气 App 意味着什么 这是用英语运行的 App 在右边您可以看到 它用阿拉伯语运行的情况 很明显 不仅翻译适应了语言 布局也遵循了适当的方向性 如果您想了解更多 关于如何创建适用于 所有语言的布局以及哪些类型的符号 提供了本地化的替代方案 以及对于从右到左书写的语言 还需要考虑什么 请务必观看演讲 “Get it right... to left”
在这里 右边是用印度语 运行的 App 让我们放大看看 这种语言的脚本往往更高 如果您仔细观察 您会发现标签的高度 也相应地调整了 系统会自动完成这项任务 您所要做的就是确保您没有 给 UI 元素一个固定的高度 不要假定所有文字 都能在 44 像素点以内 只是因为它足以放下英文字符串 请根据不同的情况 做好您的文字会更高的准备
回到主视图 滚上去 天气有一个 10 天的预测视图 便于查看下个星期的天气
这个屏幕上最引人注目的 是它如何根据最长的标签 动态调整元素的位置 在英语中 Today 比所有 工作日名称的缩写都要长 但是 在西班牙语中 它们都有三个字符宽 而在希腊语中 “今天”一词的长度几乎是两倍 不过 在所有语言中 天气图标都是垂直对齐的 这意味着它们与相邻元素之间 没有固定的间隔 而是根据 “最长工作日” 标签流动 在创建与国际化配合良好的布局时 您应该始终记住标签需要灵活 您已经看到了使它们 在垂直方向上具有灵活性是多么重要 但同时也准备好标签会随着 较长的译文在水平方向上增长 在某些布局中 比如在这个例子中 要适应这一点可能是一个挑战 但今年 SwiftUI 增加了对 Grid 的支持 这是一个新的视图 可以帮助您更易于构建这种布局 让我们仔细看看如何使用 Grid 首先 您要先用前导对齐来声明 Grid 这意味着 UI 元素在从左到右 书写的语言中 会从屏幕的左边开始 在从右到左的书写语言中 会从屏幕的右边开始 然后 为每个水平组 添加一个 GridRow 最后 要声明行内容 这就是创建这个高级布局 所需要的全部内容 当标签需要更多的空间时 Capsule 可以缩小大小 因为它是最灵活的元素 SwiftUI 完成了所有繁重的工作 如测量 改变大小 定位视图 这完全是自动的 另一个挑战是在有限的空间内 比如在 Apple Watch 上 使用较长的翻译作品制作视图 在这里 Tip Function 的 德语翻译太长了 无法放在一行里 我们不用为解决这个问题删除 文本旁的图标 以腾出更多空间 解决方案是在需要时 使用两行或两行以上的文本 这是默认行为 如果没有足够的空间 我们不鼓励您 改变或者隐藏界面元素 通常会有一种调整布局的方法 使其能够适应语言的需要 邮件 App 以一种创造性的方式 做到了这一点
在表单演示中 有四个按钮 能对这封电子邮件执行行动 当一个按钮标题的翻译太长时 我们不用剪切文本或换行 这会让视图看起来不平衡 相反 整个布局从水平堆(Horizontal Stack) 过渡为了两行垂直堆
今年 SwiftUI 增加了另一个 很棒的工具 使创建动态布局更容易 它就是 ViewThatFits 本质上 它会允许您在空间受限和 视图不适合的情况下提供替代的布局
您只需声明您的视图彼此独立 并把它们放在 ViewThatFits 中 SwiftUI 会自动检测视图 是否不适合 但不会进行剪切 并切换到提供的下一个视图 记住 您应该只切换布局 仅仅因为翻译太长而隐藏视图 是一种糟糕的做法 这会使得用户更难使用 UI 通过灵活的布局 尽量为所有界面元素 腾出空间
这不仅有助于本地化 当用户喜欢更小或更大的文本 并且使用不同的设备时 这种布局也会很有效 如果您想要了解更多今年 SwiftUI 出色的新布局功能 我建议您观看演讲 “Compose custom layouts with SwiftUI” 拥有不同的辅助功能偏好设置 和本地化文本对布局来说是一个挑战 界面元素可以更高更宽 调整布局以适应它可能是一项挑战 但今年有了 SwiftUI 就容易多了
我希望您从这次演讲中了解到 在支持其他语言时 在代码中构造字符串 是很有挑战性的 要听取全球用户和测试人员的反馈 确保所有人都能顺利使用 在 Swift 中格式化值很简单 通常只需要一行代码 这样 格式化的值 就会自动地顺应用户的偏好设置
当您提供一个 Swift 软件包时 利用新的 Xcode 本地化工作流程 为您的客户端提供完全本地化的体验 现在 无论使用 SwiftUI 与否 您的布局都应该能够适应翻译文本 和辅助功能的设置 使用您的布局工具使布局灵活 而不隐藏界面元素 最后 您的用户会对此感到庆幸的 因为他们会希望您的 App 能融入他们的生活 这包括尊重他们的语言 现在 我正期待着一个 阳光灿烂的星期 请享受余下的 WWDC 感谢观看
-
-
1:59 - Declare strings using String(localized)
let windPerceptionLabelText = String( localized: "Wind is making it feel cooler", comment: "Explains the wind is lowering the apparent temperature" )
-
2:46 - Translation example 1
let filter = String(localized: "Archive.label", defaultValue: "Archive", comment: "Name of the Archive folder in the sidebar") let filter = String(localized: "Archive.menuItem", defaultValue: "Archive", comment: "Menu item title for moving the email into the Archive folder")
-
3:40 - Translation example 2
String(localized: "Show weather in \(locationName)", comment: "Title for a user activity to show weather at a specific city") String(localized: "Show weather in My Location", comment: "Title for a user activity to show weather at the user's current location")
-
4:58 - Comment example
String(localized: "Show weather in \(locationName)", comment: "Title for a user activity to show weather at a specific city")
-
6:40 - Localized remote content example
let allServerLanguages = ["bg", "de", "en", "es", "kk", "uk"] let language = Bundle.preferredLocalizations(from: allServerLanguages).first
-
7:56 - Numbers in a string example 1
String(localized: "\(amountOfRain) in last \(numberOfHours) hour", comment: "Label showing how much rain has fallen in the last number of hours") String(localized: "\(amountOfRain) in last ^[\(numberOfHours) hour](inflect: true)", comment: "Label showing how much rain has fallen in the last number of hours")
-
8:40 - Numbers in a string example 2
if selectedCount == 1 { return String(localized: "Remove this city from your favorites") } else { return String(localized: "Remove these cities from your favorites") }
-
9:00 - Numbers in a string example 3
String(localized: "\(amountOfRain) in last ^[\(numberOfHours) hour](inflect: true).", comment: "Label showing how much rain has fallen in the last number of hours")
-
9:29 - Formatter example
let humidity = 54 // In a SwiftUI view Text(humidity, format: .percent) // In Swift code humidity.formatted(.percent)
-
10:03 - Formatter example 2
date.formatted( .dateTime.year() .month() ) // Jun 2022 whatToExpect.formatted() // New features, exciting API, and advanced tips amountOfRain.formatted( .measurement( width: .narrow, usage: .rainfall)) // 12mm (date...<later).formatted( .components( style: .wide ) ) // 24 minutes, 18 Seconds date.formatted( .relative( presentation: .numeric ) ) // 2 minutes ago let components = PersonNameComponents() … nameComponentsFormatter .string(from: components) // Andreas Neusüß or 田中陽子 excitementLevel.formatted( .number .precision( .fractionLength(2) ) ) // 1,001.42 price.formatted( .currency( code: "EUR" ) ) // $20.99 distance.formatted( .measurement( width: .wide, usage: .road) ) // 500 feet bytesCopied.formatted( .byteCount( style: .file )) // 42.23 MB
-
11:10 - Combine a formatter with text
func expectedPrecipitationIn24Hours(for valueInMillimeters: Measurement<UnitLength>) -> String { // Use user's preferred measures let preferredUnit = UnitLength(forLocale: .current, usage: .rainfall) let valueInPreferredSystem = valueInMillimeters.converted(to: preferredUnit) // Format the amount of rainfall let formattedValue = valueInPreferredSystem .formatted(.measurement(width: .narrow, usage: .asProvided)) let integerValue = Int(valueInPreferredSystem.value.rounded()) // Load and use formatting string return String(localized: "EXPECTED_RAINFALL", defaultValue: "\(integerValue) \(formattedValue) expected in next \(24)h.", comment: "Label - How much precipitation (2nd formatted value, in mm or Inches) is expected in the next 24 hours (3rd, always 24).") }
-
12:22 - Stringsdict examples in English and Spanish
Localizable.stringsdict English: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>EXPECTED_RAINFALL</key> <dict> <key>NSStringLocalizedFormatKey</key> <string>%#@next_expected_precipitation_amount_24h@</string> <key>next_expected_precipitation_amount_24h</key> <dict> <key>NSStringFormatSpecTypeKey</key> <string>NSStringPluralRuleType</string> <key>NSStringFormatValueTypeKey</key> <string>d</string> <key>other</key> <string>%2$@ expected in next %3$dh.</string> </dict> </dict> </dict> </plist> Localizable.stringsdict Spanish: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>EXPECTED_RAINFALL</key> <dict> <key>NSStringLocalizedFormatKey</key> <string>%#@next_expected_precipitation_amount_24h@</string> <key>next_expected_precipitation_amount_24h</key> <dict> <key>NSStringFormatSpecTypeKey</key> <string>NSStringPluralRuleType</string> <key>NSStringFormatValueTypeKey</key> <string>d</string> <key>one</key> <string>Se prevé %2$@ en las próximas %3$d h.</string> <key>other</key> <string>Se prevén %2$@ en las próximas %3$d h.</string> </dict> </dict> </dict> </plist>
-
13:40 - Swift Package localization example
let package = Package( name: "FoodTruckKit", defaultLocalization: "en", products: [ .library( name: "FoodTruckKit", targets: ["FoodTruckKit"]), ], … )
-
14:41 - Loading a string in a Swift Package
let title = String(localized: "Wind", bundle: .module, comment: "Title for section that shows data about wind.")
-
18:19 - Grid example
// Requires data types "Row" and "row" to be defined struct WeatherTestView: View { var rows: [Row] var body: some View { Grid(alignment: .leading) { ForEach(rows) { row in GridRow { Text(row.dayOfWeek) Image(systemName: row.weatherCondition) .symbolRenderingMode(.multicolor) Text(row.minimumTemperature) .gridColumnAlignment(.trailing) Capsule().fill(Color.orange).frame(height: 4) Text(row.maximumTemperature) } .foregroundColor(.white) } } } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。