1 个不稳定版本

0.3.0 2024年4月11日

#167国际化 (i18n)

BSD-3-Clause

245KB
5.5K SLoC

{iced} 应用框架

Rizzen Yazston :iced-url: https://crates.io/crates/iced :iced_aw-url: https://crates.io/crates/iced_aw :i18n-url: https://crates.io/crates/i18n-rizzen-yazston :icu-url: https://crates.io/crates/icu :icu4x-url: https://icu4x.unicode.org/ :iced: pass:q[iced]

欢迎使用 {iced} 应用框架 项目。

目标是提供一个用于开发原生多窗口 {iced} 应用程序的起始框架。

该项目使用 {iced-url}[{iced}] 库 Crates(包括 {iced_aw-url}[iced_aw] 社区 Crates 以提供额外的控件)来构建应用程序的 GUI。

此外,框架通过使用 {i18n-url}[i18n-rizzen-yazston] Crates 和 {icu4x-url}[ICU4X] 项目的各种 Crates(主 Crates 为 {icu-url}[icu])作为功能选项来支持国际化。

为了支持各种应用程序,所有应用程序的功能能力都通过构建功能选项进行了限制(请参阅功能部分)。未使用的功能可以简单地从应用程序中删除,从而通过减少对 #[cfg(...)]#[cfg(not()...)] 语句的需求来简化源代码。

功能

以下功能可用

  • log:启用应用程序的日志记录,并在首选项窗口中插入日志级别设置,

  • sync:使用 sync::Arc 而不是 rc::Rc,以及它们各自的变体。

  • i18n:启用国际化支持。设计允许所有脚本,尽管目前仅支持自上而下的脚本,因为 icu 目前仅具有自上而下的脚本流向信息(计划扩展到所有脚本)。使用最新的 i18n 版本 0.9.1,该版本添加了新功能。

  • persistent:指定是否在退出时保存会话数据,并在应用程序启动时恢复。如果想要应用程序设置在使用过程中持久存在,则此功能是必需的。

  • first_use:启用简化首用偏好设置窗口,在首次使用时首先显示,允许用户设置特定的偏好设置,然后再打开应用程序的主窗口。此功能会自动启用 persistent 功能。

  • clap:启用命令行支持,适用于喜欢将选项/命令等传递给应用程序的应用程序。注意使用的版本是 4.4.3,因为 4.5 需要 rustc 版本 0.74。

Cargo.toml 中有两行 default,其中一行已被注释。一行启用所有功能,而另一行则启用无功能。

包含的内容

应用程序框架具有以下功能

  • 如果为应用程序构建了 first_usei18n 功能,则偏好设置窗口将在首次使用时显示,提示用户选择用户界面语言(目前正在使用语言标签,等待 ICU4X 中的 display name 功能完成),

  • 以下窗口

  • ConfirmExit:用于演示目的,应用程序在退出时被设置为显示(模拟未保存的数据),

  • Preferences:包含用户界面语言设置和可选的日志级别设置,

  • FatalError:用于向用户显示致命错误消息(当未从控制台启动时很有用),

  • Information:一个简单的通用窗口,用于向用户显示消息,

  • Main:仅包含菜单栏,

  • About:简单地演示关于窗口。

  • 当弹出窗口显示时,通常禁用父窗口,

  • 捕获窗口装饰关闭按钮,以处理某些状态情况,

  • 窗口可调整大小和位置,并且如果构建了 persistent 功能,则其最终位置和大小将在应用程序终止时保存,并在应用程序重新启动时恢复。

  • 支持内部处理 Result 错误的 update() 方法以及 'Application::new()' 方法,使用致命错误窗口显示未捕获的错误。

  • 支持国际化的文本和错误本地化。包含两个用于几乎所有文本的演示语言。故意不将主窗口中显示的文本本地化,以进行演示。

  • 对于选定平台上的本地化提供了一个简单的示例。对于 MacOS 目标,菜单栏和确认退出窗口使用 "退出 <app_name>" 而不是 "退出"。

使用方法

注意:没有包含构建脚本,并且需要将数据文件复制到目标位置。

由于此项目是多窗口 {iced} 应用程序开发的起点,它可以编译成一个功能示例,并通过使用应用程序名称 example 来启动。

在启动 example 之前,将 l10n 目录复制到二进制文件所在的目录,以避免因缺少本地化数据库而导致的恐慌。

编辑项目根目录下的 lib.rs,以配置各种应用程序的 const 以反映新的项目。

由于这是一个用于创建多窗口应用的微型应用框架,您可以自由删除不需要的功能,这些功能可以通过 #[cfg(...)] 语句和删除相关的语句/表达式来轻松识别。或者,您可以保留这些功能不变,并继续使用新窗口和现有窗口的新组件的 #[cfg(...)] 语句,以便在以后方便切换到更高级的功能(如国际支持或突然需要命令行选项)。

注意

  • 菜单项始终居中,iced_awmenu 的当前实现没有方法或手段来更改对齐以从开始或结束。

  • 这仍然是一个正在进行中的项目,因此窗口可能看起来有点奇怪。目前更注重功能而不是外观。

添加新的窗口

  • src/window 目录中,选择一个与您的新窗口布局结构最接近的窗口,复制一个带有新文件名的 Rust 文件。

  • 在新窗口的 .rs 文件中进行必要的更改

  • 例如,重命名 ???Localisation 结构体,??? 结构体和 display_??? 函数,其中 ??? 是窗口缩写名称。根据需要调整这些内容。

  • 如有必要,添加一个 ???Message 枚举和一个 update_??? 函数,其中 ??? 是内部窗口缩写名称。请参阅现有的 preferences.rs 以获取示例。

  • 修改 try_new()try_update()view() 的内容,并可选地调整 parent_remove()

  • window.rs 中添加新文件名。

  • core/session.rs 中为窗口在 Ui 结构体中添加条目。

  • core/application

  • use crate::{ ... window::{ 语句中添加新窗口文件名。

  • WindowType 添加新窗口的条目。

  • 如果新窗口有自己的 Message 枚举,将其添加到 ApplicationMessage 枚举中,以便能够将消息传递到新窗口的 try_update() 方法。

  • 针对try_update()方法,为新的窗口添加匹配分支,可以是直接添加到窗口的try_update()方法中,或者如果需要在窗口的try_update()方法之外执行更多逻辑,可以在新窗口的Rust文件中添加一个update_?函数,其中?是窗口的缩写。参见其他分支的示例。

  • resized()moved()方法添加新的窗口条目。

  • 如果新的窗口可以通过应用程序的菜单栏访问,则请在window/main/menu_bar.rs中添加条目,并将匹配分支添加到update_main()函数中,以处理新窗口的显示。

设计流程

几乎所有的i18n库方法都使用Result类型来能够提供可捕获的运行时错误,应用程序的开发者(或另一个库)可以决定忽略错误、显示错误或未捕获的错误成为致命错误(应用程序终止)。这是i18n项目的有意设计。

另一方面,iced库不支持将Result类型作为new()update()view()方法的返回类型。需要捕获和处理i18n各种方法的Result

创建了一种新的更新方法,称为 try_update(),该方法包含原本在应用程序的 update() 方法中所有的逻辑,并返回一个 Result 类型。该方法在 update() 中被调用,如果结果是 Ok() 变体,则将 Command 枚举返回给 iced 调用者。然而,如果结果是 Err() 变体,则创建包含错误的 FatalError 状态,并将生成的窗口创建命令返回给 iced 调用者。显示的致命错误窗口是一种特殊类型的窗口,它不允许返回 Err() 变体。在致命错误窗口的 try_update() 方法中发生的任何错误都被捕获和处理,因此只返回包含关闭所有窗口的批量命令的 Ok() 变体。在应用程序关闭之前显示运行时致命错误的好处是,当应用程序不是从通常显示错误的控制台启动,并且不支持将错误记录到日志系统(通常是文件)时。

对于 new() 方法也使用了类似的方法,实际的逻辑放在一个新的方法 try_new() 中。如果结果是错误,则应用程序以包含错误简单格式化消息的 panic!() 终止。否则,返回 Ok() 变体的内容。

没有与view()方法等价的try_view()方法,因为不应当发生错误。view()方法必须只读取窗口状态,并根据该状态构建窗口。在创建时的窗口状态必须包含所有需要显示的数据,无需任何格式化。view()方法仅允许通过读取窗口状态的字段来更改放置顺序。如果启用了功能i18n,则文本本地化仅在窗口状态的创建时,或在更新窗口状态的try_update()try_update_localisation()方法中进行。然而,应用程序的主view()方法在检索窗口的实际view()时,会捕获两种可能的错误,在这种情况下,主窗口的内容会被错误信息替换。

如上所示,有关于应用程序主try_update()view()方法的引用,调用窗口的实际try_update()view()。将更新和视图逻辑分离到每个窗口自己的方法中,这种方法是因为匹配语句变得过于庞大,难以理解各个窗口的逻辑。为此,引入了WindowTypeWindowTrait(以及WindowTrait以实现从Any向下转换),以提供一个调用窗口实际try_update()view()方法的统一方式。这还允许使用枚举WindowType将窗口编号或标识符作为String使用,当存在多个相同类型的窗口时。在窗口的try_update()view()方法中,枚举变体的值用于对特定窗口的WindowType变体进行更改。

如果应用程序的主要 Message 枚举中没有包含适当的消息处理,则 Message 枚举将被分解为单独的 Message 枚举,每个窗口一个。

依赖关系

~31–58MB
~874K SLoC