#icu #unicode #localization #native-bindings #date-time

rust_icu

Unicode 的 ICU4C 库的本地绑定

24 个版本 (13 个稳定版本)

5.0.0 2024 年 2 月 21 日
4.2.3 2023 年 10 月 6 日
4.0.0 2023 年 5 月 2 日
3.0.0 2022 年 11 月 10 日
0.3.0 2020 年 6 月 12 日

国际化 (i18n) 中排名 #240

Download history 21/week @ 2024-04-21 1/week @ 2024-04-28 21/week @ 2024-07-07 110/week @ 2024-07-28

每月下载 131

Apache-2.0

2MB
48K SLoC

rust_icu:ICU 库的底层 Rust 语言绑定

项目 描述
测试 Test status
源代码 https://github.com/google/rust_icu
README https://github.com/google/rust_icu/blob/main/README.md
覆盖率 查看报告
文档 https://docs.rs/crate/rust_icu

这是一个用于 C(即 ICU4C)的 Unicode 国际组件(ICU)库的底层本地 Rust 语言绑定的库。

如果您只需要快速了解如何下载和安装,请参阅快速入门指南

有关 ICU 库的详细信息,请参阅ICU 项目主页。库源代码可以在Github上查看。

此文件的最新版本可在https://github.com/google/rust_icu找到。

这不是一个官方支持的产品。

为什么要包装 ICU(而不是做其他事情)?

  • rust 语言国际化页面确认,rust 中的 ICU 支持不完整,因此拥有一个功能性的包装器有助于推进技术的发展。

  • 例如,Fuchsia 这样的项目已经依赖 ICU,而 rust 绑定允许以简单的方式使用 Unicode 算法,而无需承担更多依赖项。

  • ICU4X 等项目的接口合作可能允许在未来无缝过渡到全 Rust 实现。

仓库结构

该仓库按 rust 包工作区组织。每个包对应于 ICU4C 库 C API 中的相应头文件。有关头文件中函数覆盖的详细信息,请参阅覆盖率报告

描述
rust_icu 顶级包。如果您只想使用所有功能,请包含此包。
rust_icu_common 常用的绑定低级包装。
rust_icu_intl 实现 ECMA 402 建议的 API。
rust_icu_sys 低级别绑定代码
rust_icu_ubrk 支持文本边界分析。实现了来自 ICU 库的 C API 头文件 ubrk.h
rust_icu_ucal ICU 日历。实现了来自 ICU 库的 C API 头文件 ucal.h
rust_icu_ucol 排序支持。实现了来自 ICU 库的 C API 头文件 ucol.h
rust_icu_udat ICU 日期和时间。实现了来自 ICU 库的 C API 头文件 udat.h
rust_icu_udata ICU 二进制数据。实现了来自 ICU 库的 C API 头文件 udata.h
rust_icu_uenum ICU 枚举。实现了来自 ICU 库的 C API 头文件 uenum.h。主要实现 UEnumeration 和相关功能。
rust_icu_uformattable 支持区域敏感的列表格式化。实现了来自 ICU 库的 C API 头文件 uformattable.h。自 0.3.1 版本开始。
rust_icu_ulistformatter 支持区域敏感的列表格式化。实现了来自 ICU 库的 C API 头文件 ulistformatter.h
rust_icu_uloc 支持区域。实现了来自 ICU 库的 C API 头文件 uloc.h
rust_icu_umsg 支持 MessageFormat。实现了来自 ICU 库的 C API 头文件 umsg.h
rust_icu_unorm2 支持 Unicode 正规化。实现了来自 ICU 库的 C API 头文件 unorm2.h
rust_icu_unum 支持数字格式化。实现了来自 ICU 库的 C API 头文件 unum.h
rust_icu_unumberformatter 支持数字格式化(现代)。实现了来自 ICU 库的 C API 头文件 unumberformatter.h
rust_icu_upluralrules 支持区域敏感的复数规则。实现了来自 ICU 库的 C API 头文件 upluralrules.h
rust_icu_ustring ICU 字符串。实现了来自 ICU 库的 C API 头文件 ustring.h
rust_icu_utext 文本操作。实现了来自 ICU 库的 C API 头文件 utext.h
rust_icu_utrans 支持转写。实现了来自 ICU 库的 C API 头文件 utrans.h

限制

目前生成的 Rust 语言绑定方法将语言绑定的可用性限制在可用的 C API 中。ICU 库的 C API(在文档中有时称为 ICU4C)与 ICU C++ API 不同。

此库提供的绑定适用性有限,这意味着它可能有时不会直接适用于您。如果您遇到这种情况,请随时提交错误报告以便我们修复。欢迎Pull requests

我们目前知道的限制如下

  • 没有保证功能一致性。一些用C++实现的算法没有C等价物,反之亦然。如果你从C++使用库,通常这不是问题,因为你可以选择任何适合你的API界面。但对于Rust绑定来说,这是一个问题,因为我们目前只能使用C API。

  • C++中一个新算法的实现并不一定总是反映在C API中,导致C和C++ API界面之间存在功能差异。例如,参见这个错误

  • 虽然使用icu_config功能可能会让你在一定程度上自由地为你的库版本自动生成绑定,但我们仍然需要保持一个显式支持的ICU版本列表,以确保包装器稳定。

兼容性

兼容性保证如下

  1. 对所有感兴趣的功能组合,都会为最后三个主要的ICU库版本执行自动测试。
  2. 会对docs.rs系统中使用的ICU库版本执行自动测试(因此可以构建文档)。
rust_icu版本 ICU 63.x ICU 70.1 ICU 71.1 ICU 72.1 ICU 73.1 ICU 74.1
3.0
4.0
5.0

功能

rust_icu库旨在使用cargo编译,并启用以下功能之一。使用cargo编译允许我们在rust_icu_sys库中的自定义build.rs文件中执行一些库检测,并将构建过程适应您的构建环境。然而,由于并非每个开发环境都会使用相同的设置,我们选择了以下某些功能(如下)作为配置选项。

虽然我们的意图是确保以下功能的列表与实际的Cargo.toml列表保持最新,但该列表可能会定期过时。

要使用任何功能,您需要在打算使用的所有rust_icu_*crates中激活该功能。未能这样做会导致编译结果令人困惑。

功能 默认? 描述
use-bindgen 如果设置,cargo将运行bindgen以根据已安装的ICU库生成绑定。程序icu-config必须在$PATH中才能工作。将来可能会有其他自动检测库的方法,例如通过pkg-config
renaming 如果设置,将使用版本号附加到ICU绑定上。这在ICU中被称为“重命名”,通常仅在需要链接到特定ICU版本时需要,例如绕过必须链接不同ICU版本的问题。有关重命名的讨论,请参见ICU文档如果不使用bindgen,则必须使用此功能。
icu_config 如果设置,将使用二进制icu-config来配置库。如果您不想让build.rs尝试自动检测构建环境,请关闭此功能。如果您希望以不同的方式配置ICU,则应跳过此功能。此功能仅在bindgen功能使用时才有意义;否则它没有效果。
icu_version_in_env 如果设置,将为在环境变量RUST_ICU_MAJOR_VERSION_NUMBER中指定的ICU版本生成ICU绑定,该变量在构建时提供给cargo。有关如何使用此功能的详细信息,请参阅下面的部分。此功能仅在bindgen功能不使用时才有意义;否则它没有效果。
静态 如果设置,则静态链接 ICU 库(包括标准 C++ 的动态库)。您可以使用 RUST_ICU_LINK_SEARCH_DIR 来添加额外的搜索路径,如果您在非标准目录中有一个 ICU 构建版本。

先决条件

必需

  • rust_icu 源代码

    使用 git 进行克隆

    git clone https://github.com/google/rust_icu.git
    
  • rustup

    https://rustup.rs 安装。用于设置工具链默认值。这将安装 cargo

  • Clang

    您必须安装 Clang 以访问正确的头文件。

  • ICU 库开发环境

    您将需要访问 ICU 库,以便 rust_icu 绑定可以链接。ICU 的下载和安装超出了本文件的范畴。请阅读 ICU 简介 以了解如何构建和安装。

    有时,ICU 库可能已经预安装在您的系统上,或者您可以从包管理程序中获取该库。然而,这个库并不一定是您需要链接到您正在开发的程序中的库。简而言之,您有责任在您的系统上的某个地方有 ICU 开发版本的副本。

    我们有一个 快速入门安装,这可能会在您的环境与我们的环境非常相似且您想从源代码构建 ICU 的情况下,使您顺利开始。

可选

  • 如果您想使用基于 make 的构建和测试,则需要 GNU Make。

    安装 GNU Make 超出了本文件的范畴。请参考您的操作系统说明进行安装。

  • 如果决定使用基于 docker 的构建和测试,则需要 docker

    安装 docker 超出了本文件的范畴,请参阅 docker 安装说明 以获取详细信息。由于安装 docker 会影响主机机器,您的公司可能有一份关于如何正确安装 docker 的内部文档。

  • 如果使用 icu_config 功能,则需要 icu-config 工具。

    您需要在您的系统上安装 ICU 库,使得二进制 icu-config 在您的 $PATH 中的某个位置。构建脚本将使用它来发现库设置并生成正确的链接脚本。如果您使用该功能但找不到 icu-config

  • 如果使用 bindgen 功能,则需要 bindgen 工具。

    有关如何安装的说明,请参阅 bindgen 用户指南

  • 如果使用 bindgen 功能,则需要 rustfmt 工具。

    有关如何安装的说明,请参阅 https://github.com/rust-lang/rustfmt

测试

运行 rust_icu 的测试有一些选项。

Cargo

使用 cargo 构建 和 测试是构建和测试 rust 代码的标准方式。

rust_icu 库的情况下,您可能会发现您系统上的默认 ICU 开发包很旧,在这种情况下,您需要自己构建 ICU4C 库(下面有说明)。这将使您需要传递 PKG_CONFIG_PATHLD_LIBRARY_PATH 环境变量来帮助构建代码定位和使用您构建的库,而不是系统默认库。

以下测试都应该能够构建并通过。请注意,由于所需的库位于自定义位置,我们在运行测试时需要设置LD_LIBRARY_PATH,以及PKG_CONFIG_PATH

如果你发现可以使用系统默认的ICU安装,你可以安全地省略这两个库。

env PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig" \
    LD_LIBRARY_PATH="$HOME/local/lib" \
        bash -c 'cargo test'

如果你认为上述方法过于麻烦,可以考虑尝试基于Docker的方法

GNU Make

如果你喜欢GNU的方式做事,你可能喜欢GNU Make方法。

最简单的方法是使用GNU Make并运行

make test

如果你正在工作于rust_icu,并且你的开发环境已经设置好,希望有一个简短的运行测试的方法,你可能想使用这种方法。

基于Docker

参见上方的可选依赖部分

要运行rust_icu源代码的不可变构建和测试,请执行以下命令

make docker-test

这将在本地的机器上运行基于Docker的源代码构建和测试。这是一个测试代码是否与特定参考版本的ICU一起工作的好方法。

现有技术

已有许多现有技术被考虑过

目前的情况是,我想先自己做一些实验,然后看看这些工作是否可以合并到上述任何一项努力中。

另请参阅

假设

对于ICU绑定有几种竞争方法。然而,根据rust的RFC存储库中的信息,似乎rust对ICU的支持工作仍在进行中。

这是在制作这个库时所做的假设

  • 我们需要一个完整、可重用且无痛苦的rust ICU低级库。

    例如,这意味着我们必须依赖于外部ICU库,而不是将库本身与绑定代码一起拖动。这种模块化允许库的最终用户使用他们选择的ICU库,并将其纳入他们各自的系统中。

  • 本库的工作不会重新实现任何ICU算法。

    ICU重新实现可能需要数千名工程师年才能完成。对于像ICU这样微妙和复杂的API,我认为维护单个集中实现可能是一个更好的投资回报率。

    此外,这个库的存在并不会阻止重新实现。如果有人想尝试重新实现ICU,那也很好。

  • 这个库应作为rust实现的低级基础。

    低级ICU API可能不适合最终用户。应该在绑定之上构建一个rust-ful API。可能最好将此功能细分为crates,以符合rust开发者的期望。

    我很乐意重用上述提到的项目中已做的逻辑细分。

  • 我想探索与现有实现相结合以构建完整的rust ICU支持的方法。

    希望有可能将所有可用的rust绑定的优点结合到一个统一的rust库中。我始终愿意讨论选项。

    我之所以没有向“现有技术”部分中列出的任何项目贡献,而是开始了独立的工作,唯一的原因是我想尝试在 Rust 中生成的库会是什么样子。

附加说明

快速入门指南

在开始之前,请确保满足以下先决条件

  • 您已安装 Docker 并在您的系统上运行。
  • 您拥有 GNU Make。
  • 您有 git
  • 您有足够的磁盘空间。构建环境的 Docker 镜像相当大,因此需要几吉字节的空间才能全部安装。
  • 您有互联网连接。

从那里开始,以下命令序列将检出、构建和测试 rust_icu 源代码。

mkdir -p ~/tmp
cd tmp
git clone https://github.com/google/rust_icu
cd rust_icu
make docker-test

您现在可以修改代码和测试。您可以通过运行 make docker-test 来重新运行编译和测试循环。

ICU 安装说明

以下说明遵循 ICU 仓库 中的“树外”构建说明。

假设

以下说明不是自包含的。它们假设

  • 您已经设置了系统,可以有效地遵循 ICU 构建说明。这需要一些前期时间投资。
  • 您可以从源代码构建 ICU,并且您的项目可以访问 ICU 源代码。
  • 您的设置是 Linux,有一些非常具体的设置,对我来说是有效的。您可能能够将它们适配到您的系统上。

编译

mkdir -p $HOME/local
mkdir -p $HOME/tmp
cd $HOME/tmp
git clone https://github.com/unicode-org/icu.git
mkdir icu4c-build
cd icu4c-build
../icu/icu4c/source/runConfigureICU Linux \
  --prefix=$HOME/local \
  --enable-static
make
make install
make doc

如果编译成功完成,则目录 $HOME/local/bin 将包含文件 icu-config,这是发现库配置所必需的。

您也可以执行以下操作

make check

来运行单元测试。

如果您将 $HOME/local/bin 添加到 $PATH,或者将 icu-config 移动到您的 $PATH 中列出的目录中,那么您应该已经准备好编译 rust_icu

ICU 重建说明

如果您更改 ICU 库的配置,目的是从源代码重新构建库,那么您可能需要添加一个中间的 make clean 命令。

由于 ICU 构建不是密封的,这确保了构建目录中没有旧编译过程的残留物。例如,如果您升级 ICU 库的主要版本,则需要这样做。如果您忘记这样做,那么在编译 ICU、链接或运行程序时可能会看到意外的错误。

为特定版本的 ICU 编译

假设

  • 您已选择功能集 [renaming,icu_version_in_env]o

或者:

  • 您已手动验证 兼容性矩阵 中您想要使用的 ICU 版本和功能集有“是”。

以下是一个测试示例。

env PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig" \
    LD_LIBRARY_PATH="$HOME/local/lib" \
    RUST_ICU_MAJOR_VERSION_NUMBER=65 \
        bash -c 'cargo test'

以下是一个尚未经过测试的示例,说明如何针对现有的ICU版本66编译rust_icu

env PKG_CONFIG_PATH="$HOME/local/lib/pkgconfig" \
    LD_LIBRARY_PATH="$HOME/local/lib" \
    RUST_ICU_MAJOR_VERSION_NUMBER=66 \
        bash -c 'cargo test'

添加对ICU新版本的支持。

一般来说,只要支持icu-config方法,就应该能够为ICU库的新版本生成库包装器,前提是底层C API没有太大差异。

实现ICU 65.1轻松支持的方法包括以下步骤。下面,$RUST_ICU_SOURCE_DIR是您提取ICU源代码的目录。

  • 将新的ICU版本从源代码下载到$RUST_ICU_SOURCE_DIR
  • 按照上述步骤使用新版本构建ICU库。
  • 从输出目录$RUST_ICU_SOURCE_DIR/target/debug/build/rust_icu_sys-...获取文件lib.rs,将其重命名为lib_66.rs(如果使用ICU版本66,否则添加您使用的版本)。
  • 将文件保存到目录$RUST_ICU_SOURCE_DIR/rust_icu_sys/bindgen,这是包含预生成源文件的目录。

如果build.rs被修改为包含更多功能,可能需要重新生成这些文件lib_XX.rs

添加更多绑定

当添加更多的ICU包装器时,请确保执行以下操作

  • 检查rust_icu_sys/build.rsrust_icu_sys/bindgen/run_bindgen.sh,以将适当的行添加到BINDGEN_SOURCE_MODULES,然后是BINDGEN_ALLOWLIST_FUNCTIONSBINDGEN_ALLOWLIST_TYPES

开启特定功能集进行测试

这是一个在ICU 67上运行docker测试的示例,启用了icu_version_in_envrenaming功能,而不是默认值。请注意,参数主要通过环境变量传递给运行docker-test的容器。

make DOCKER_TEST_ENV=rust_icu_testenv-67 \
  RUST_ICU_MAJOR_VERSION_NUMBER=67 \
  DOCKER_TEST_CARGO_TEST_ARGS='--no-default-features --features icu_version_in_env,renaming' \
  docker-test

一些说明

  • 环境变量RUST_ICU_MAJOR_VERSION_NUMBER用于icu_version_in_env功能,以指导cargo使用文件rust_icu_sys/bindgen/lib_67.rs作为预构建的bindgen源文件,而不是尝试动态生成。
  • 环境变量DOCKER_TEST_CARGO_TEST_ARGS用于将命令行参数传递给在docker容器中使用的cargo test。这些环境变量未经引号原样传递到cargo test,因此环境中的单词最终成为cargo test的单独参数。
  • 环境变量DOCKER_TEST_ENV是运行测试所使用的Docker容器的基名。容器rust_icu_testenv-67是一个包含预安装环境(已编译的ICU 67版本)的容器镜像。

刷新静态bindgen文件

需要Docker。

定期运行make static-bindgen,以刷新静态生成的bindgen文件(命名为lib_XX.rs,其中XX是ICU版本,例如67),这些文件位于目录rust_icu_sys/bindgen中,当关闭bindgen功能时使用。

调用此make目标将修改本地签出的lib_XX.rs文件的较新版本。提交一个pull request并检查它们。

有关为什么需要此信息的更多信息,请参阅bindgen README.md

依赖项

~0.4–1.1MB
~24K SLoC