diff --git a/Cargo.lock b/Cargo.lock index 1ca66a601..624f9c867 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -793,9 +793,9 @@ dependencies = [ [[package]] name = "calendrical_calculations" -version = "0.1.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27ca2b6e2f7d75f43e001ded6f25e79b80bded5abbe764cbdf78c25a3051f4b" +checksum = "5abbd6eeda6885048d357edc66748eea6e0268e3dd11f326fff5bd248d779c26" dependencies = [ "core_maths", "displaydoc", @@ -1791,9 +1791,9 @@ checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" [[package]] name = "fixed_decimal" -version = "0.5.6" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0febbeb1118a9ecdee6e4520ead6b54882e843dd0592ad233247dbee84c53db8" +checksum = "79c3c892f121fff406e5dd6b28c1b30096b95111c30701a899d4f2b18da6d1bd" dependencies = [ "displaydoc", "smallvec", @@ -2375,34 +2375,59 @@ dependencies = [ [[package]] name = "icu_calendar" -version = "1.5.2" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7265b2137f9a36f7634a308d91f984574bbdba8cfd95ceffe1c345552275a8ff" +checksum = "a2b2acc6263f494f1df50685b53ff8e57869e47d5c6fe39c23d518ae9a4f3e45" dependencies = [ "calendrical_calculations", "displaydoc", "icu_calendar_data", - "icu_locid", - "icu_locid_transform", + "icu_locale", + "icu_locale_core", "icu_provider", + "ixdtf", "tinystr", - "writeable", "zerovec", ] [[package]] name = "icu_calendar_data" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "820499e77e852162190608b4f444e7b4552619150eafc39a9e39333d9efae9e1" +checksum = "118577bcf3a0fa7c6ac0a7d6e951814da84ee56b9b1f68fb4d8d10b08cefaf4d" + +[[package]] +name = "icu_casemap" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "070f98b5b82798fcb93654bf96ed9f40064fc44c86f51a09ea711092cd5cc5be" +dependencies = [ + "icu_casemap_data", + "icu_collections", + "icu_locale_core", + "icu_properties", + "icu_provider", + "potential_utf", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_casemap_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "846b0857ca091204be3c874bc93daaf89d4777e8d2d20b0d3ffe8f671d98014b" [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", + "potential_utf", + "serde", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -2410,22 +2435,22 @@ dependencies = [ [[package]] name = "icu_datetime" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d115efb85e08df3fd77e77f52e7e087545a783fffba8be80bfa2102f306b1780" +checksum = "989d56ea5bbc43ae2b4e0388874b002884eaf4ed3a76c84a6c8c5ad575e04d72" dependencies = [ "displaydoc", - "either", "fixed_decimal", "icu_calendar", "icu_datetime_data", "icu_decimal", - "icu_locid", - "icu_locid_transform", + "icu_locale", + "icu_locale_core", + "icu_pattern", "icu_plurals", "icu_provider", - "icu_timezone", - "smallvec", + "icu_time", + "potential_utf", "tinystr", "writeable", "zerovec", @@ -2433,43 +2458,50 @@ dependencies = [ [[package]] name = "icu_datetime_data" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef5f04076123cab1b7a926a7083db27fe0d7a0e575adb984854aae3f3a6507d" +checksum = "40d3cc1b690d9703202bc319692ac8a1f3a6390686f0930ff40542450fa34f0b" [[package]] name = "icu_decimal" -version = "1.5.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8fd98f86ec0448d85e1edf8884e4e318bb2e121bd733ec929a05c0a5e8b0eb" +checksum = "288247df2e32aa776ac54fdd64de552149ac43cb840f2761811f0e8d09719dd4" dependencies = [ "displaydoc", "fixed_decimal", "icu_decimal_data", - "icu_locid_transform", + "icu_locale", + "icu_locale_core", + "icu_pattern", + "icu_plurals", "icu_provider", "writeable", + "zerovec", ] [[package]] name = "icu_decimal_data" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c95dd97f5ccf6d837a9c115496ec7d36646fa86ca18e7f1412115b4c820ae2" +checksum = "6f14a5ca9e8af29eef62064f269078424283d90dbaffeac5225addf62aaabc22" [[package]] name = "icu_experimental" -version = "0.1.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "844ad7b682a165c758065d694bc4d74ac67f176da1c499a04d85d492c0f193b7" +checksum = "0a881116e620fd635f564fd9cb9bc36c256b9da2221df8b3f55643d8ef32140f" dependencies = [ "displaydoc", + "either", "fixed_decimal", + "icu_casemap", "icu_collections", "icu_decimal", "icu_experimental_data", - "icu_locid", - "icu_locid_transform", + "icu_list", + "icu_locale", + "icu_locale_core", "icu_normalizer", "icu_pattern", "icu_plurals", @@ -2479,60 +2511,81 @@ dependencies = [ "num-bigint", "num-rational", "num-traits", + "potential_utf", "smallvec", "tinystr", "writeable", - "zerofrom", "zerotrie", "zerovec", ] [[package]] name = "icu_experimental_data" -version = "0.1.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121df92eafb8f5286d4e8ff401c1e7db8384377f806db3f8db77b91e5b7bd4dd" +checksum = "f72090d4f08a2bc94565cb02de6d5b87939424e462d9927d73a34f6f8e5d1232" [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_list" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "aeeaf517689324395bed4767f7c65504f5455942ed4c14ee54c2087ca00b816e" +dependencies = [ + "icu_list_data", + "icu_locale", + "icu_provider", + "regex-automata", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_list_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed62dbf114db9a4163481ed071509c4cd52cbcef9cb85979eba08a95549d73f3" + +[[package]] +name = "icu_locale" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", + "serde", "tinystr", "writeable", "zerovec", ] [[package]] -name = "icu_locid_transform" -version = "1.5.0" +name = "icu_locale_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" +checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2546,32 +2599,32 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_pattern" -version = "0.2.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f36aafd098d6717de34e668a8120822275c1fba22b936e757b7de8a2fd7e4" +checksum = "1c4c568054ffe735398a9f4c55aec37ad7c768844553cc0978f09cc9b933a1fb" dependencies = [ "displaydoc", "either", + "serde", "writeable", "yoke", - "zerofrom", + "zerovec", ] [[package]] name = "icu_plurals" -version = "1.5.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a70e7c025dbd5c501b0a5c188cd11666a424f0dadcd4f0a95b7dafde3b114" +checksum = "2a50023f1d49ad5c4333380328a0d4a19e4b9d6d842ec06639affd5ba47c8103" dependencies = [ - "displaydoc", "fixed_decimal", - "icu_locid_transform", + "icu_locale", "icu_plurals_data", "icu_provider", "zerovec", @@ -2579,92 +2632,71 @@ dependencies = [ [[package]] name = "icu_plurals_data" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a483403238cb7d6a876a77a5f8191780336d80fe7b8b00bfdeb20be6abbfd112" +checksum = "8485497155dc865f901decb93ecc20d3e467df67bfeceb91e3ba34e2b11e8e1d" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ - "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_adapters" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc" -dependencies = [ - "icu_locid", - "icu_locid_transform", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "icu_timezone" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa91ba6a585939a020c787235daa8aee856d9bceebd6355e283c0c310bc6de96" -dependencies = [ - "displaydoc", - "icu_calendar", - "icu_provider", - "icu_timezone_data", - "tinystr", + "serde", "zerotrie", "zerovec", ] [[package]] -name = "icu_timezone_data" -version = "1.5.1" +name = "icu_properties_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adcf7b613a268af025bc2a2532b4b9ee294e6051c5c0832d8bff20ac0232e68" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_time" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3af0c141da0a61d4f6970cd1d5f4b388b17ea22f8124f8f6049d3d5147586a" +dependencies = [ + "calendrical_calculations", + "displaydoc", + "icu_calendar", + "icu_locale_core", + "icu_provider", + "icu_time_data", + "ixdtf", + "serde", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_time_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2f8aeca682d874a5247084aa4fb7d1cef9ba45d889c21209a8818dcaaa0ec9" [[package]] name = "id-arena" @@ -2691,9 +2723,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", @@ -2812,6 +2844,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "ixdtf" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ceaf4c6c48465bead8cb6a0b7c4ee0c86ecbb31239032b9c66ab9a08d2f3ee1" + [[package]] name = "jiff" version = "0.2.28" @@ -3074,9 +3112,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "litrs" @@ -3123,7 +3161,7 @@ dependencies = [ "chrono", "headers", "http", - "icu_locid", + "icu_locale_core", "mas-context", "mas-data-model", "mas-http", @@ -3412,14 +3450,12 @@ name = "mas-i18n" version = "1.20.0-rc.0" dependencies = [ "camino", - "icu_calendar", "icu_datetime", "icu_experimental", - "icu_locid", - "icu_locid_transform", + "icu_locale", + "icu_locale_core", "icu_plurals", "icu_provider", - "icu_provider_adapters", "pad", "pest", "pest_derive", @@ -4630,6 +4666,17 @@ dependencies = [ "serde", ] +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -6349,11 +6396,12 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -7777,9 +7825,9 @@ checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" dependencies = [ "either", ] @@ -7792,11 +7840,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -7804,9 +7851,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -7863,21 +7910,23 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.1.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb594dd55d87335c5f60177cee24f19457a5ec10a065e0a3014722ad252d0a1f" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", "zerofrom", + "zerovec", ] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ + "serde", "yoke", "zerofrom", "zerovec-derive", @@ -7885,9 +7934,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index f41828cab..c2a89e7be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -301,31 +301,28 @@ default-features = false # ICU libraries for internationalization [workspace.dependencies.icu_calendar] -version = "1.5.2" -features = ["compiled_data", "std"] +version = "2.2.1" +features = ["compiled_data"] [workspace.dependencies.icu_datetime] -version = "1.5.1" -features = ["compiled_data", "std"] +version = "2.2.0" +features = ["compiled_data"] [workspace.dependencies.icu_experimental] -version = "0.1.0" -features = ["compiled_data", "std"] -[workspace.dependencies.icu_locid] -version = "1.5.0" -features = ["std"] -[workspace.dependencies.icu_locid_transform] -version = "1.5.0" -features = ["compiled_data", "std"] +version = "0.5.0" +features = ["compiled_data"] +[workspace.dependencies.icu_locale] +version = "2.2.0" +features = ["compiled_data"] +[workspace.dependencies.icu_locale_core] +version = "2.2.0" [workspace.dependencies.icu_normalizer] -version = "1.5.0" +version = "2.2.0" +features = ["compiled_data"] [workspace.dependencies.icu_plurals] -version = "1.5.0" -features = ["compiled_data", "std"] +version = "2.2.0" +features = ["compiled_data"] [workspace.dependencies.icu_provider] -version = "1.5.0" +version = "2.2.0" features = ["std", "sync"] -[workspace.dependencies.icu_provider_adapters] -version = "1.5.0" -features = ["std"] # HashMap which preserves insertion order [workspace.dependencies.indexmap] @@ -740,7 +737,7 @@ version = "0.13.0" # String writing interface [workspace.dependencies.writeable] -version = "0.5.5" +version = "0.6.3" # Zero memory after use [workspace.dependencies.zeroize] diff --git a/crates/axum-utils/Cargo.toml b/crates/axum-utils/Cargo.toml index 857cbcc28..3797dfe8f 100644 --- a/crates/axum-utils/Cargo.toml +++ b/crates/axum-utils/Cargo.toml @@ -24,7 +24,7 @@ base64ct.workspace = true chrono.workspace = true headers.workspace = true http.workspace = true -icu_locid.workspace = true +icu_locale_core.workspace = true mime.workspace = true rand.workspace = true reqwest.workspace = true diff --git a/crates/axum-utils/src/language_detection.rs b/crates/axum-utils/src/language_detection.rs index 4345d382a..4f0c24259 100644 --- a/crates/axum-utils/src/language_detection.rs +++ b/crates/axum-utils/src/language_detection.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2023, 2024 The Matrix.org Foundation C.I.C. // @@ -8,7 +9,7 @@ use std::cmp::Reverse; use headers::{Error, Header}; use http::{HeaderName, HeaderValue, header::ACCEPT_LANGUAGE}; -use icu_locid::Locale; +use icu_locale_core::Locale; #[derive(PartialEq, Eq, Debug)] struct AcceptLanguagePart { @@ -90,7 +91,7 @@ impl Header for AcceptLanguage { b"*" => None, locale => { let locale = - Locale::try_from_bytes(locale).map_err(|_e| Error::invalid())?; + Locale::try_from_utf8(locale).map_err(|_e| Error::invalid())?; Some(locale) } }; @@ -156,7 +157,7 @@ impl Header for AcceptLanguage { mod tests { use headers::HeaderMapExt; use http::{HeaderMap, HeaderValue, header::ACCEPT_LANGUAGE}; - use icu_locid::locale; + use icu_locale_core::locale; use super::*; diff --git a/crates/handlers/src/oauth2/authorization/mod.rs b/crates/handlers/src/oauth2/authorization/mod.rs index 46c8eb06f..b72e58056 100644 --- a/crates/handlers/src/oauth2/authorization/mod.rs +++ b/crates/handlers/src/oauth2/authorization/mod.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2021-2024 The Matrix.org Foundation C.I.C. // @@ -154,7 +155,6 @@ pub(crate) async fn get( let res: Result = ({ let templates = templates.clone(); let callback_destination = callback_destination.clone(); - let locale = locale.clone(); async move { let maybe_session = session_info.load_active_session(&mut repo).await?; let prompt = params.auth.prompt.as_deref().unwrap_or_default(); diff --git a/crates/handlers/src/oauth2/device/link.rs b/crates/handlers/src/oauth2/device/link.rs index dedd68abb..38f55ac12 100644 --- a/crates/handlers/src/oauth2/device/link.rs +++ b/crates/handlers/src/oauth2/device/link.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2023, 2024 The Matrix.org Foundation C.I.C. // @@ -142,7 +143,7 @@ async fn handle_code( let ctx = DeviceLinkContext::new() .with_form_state(form_state) .with_csrf(csrf_token.form_value()) - .with_language(locale.clone()); + .with_language(*locale); let content = templates.render_device_link(&ctx)?; diff --git a/crates/handlers/src/oauth2/token.rs b/crates/handlers/src/oauth2/token.rs index 37c4c7497..c75e35dac 100644 --- a/crates/handlers/src/oauth2/token.rs +++ b/crates/handlers/src/oauth2/token.rs @@ -262,6 +262,7 @@ impl IntoResponse for RouteError { } impl_from_error_for_route!(mas_i18n::DataError); +impl_from_error_for_route!(mas_i18n::ParseError); impl_from_error_for_route!(mas_templates::TemplateError); impl_from_error_for_route!(mas_storage::RepositoryError); impl_from_error_for_route!(mas_policy::EvaluationError); diff --git a/crates/handlers/src/passwords.rs b/crates/handlers/src/passwords.rs index 6071cf730..23b8dd0cc 100644 --- a/crates/handlers/src/passwords.rs +++ b/crates/handlers/src/passwords.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2022-2024 The Matrix.org Foundation C.I.C. // @@ -303,8 +304,8 @@ impl Hasher { fn normalize_password(&self, password: Zeroizing) -> Zeroizing { if self.unicode_normalization { // This is the normalization method used by Synapse - let normalizer = icu_normalizer::ComposingNormalizer::new_nfkc(); - Zeroizing::new(normalizer.normalize(&password)) + let normalizer = icu_normalizer::ComposingNormalizerBorrowed::new_nfkc(); + Zeroizing::new(normalizer.normalize(&password).into_owned()) } else { password } diff --git a/crates/handlers/src/session.rs b/crates/handlers/src/session.rs index cbc18b121..2ce98555b 100644 --- a/crates/handlers/src/session.rs +++ b/crates/handlers/src/session.rs @@ -75,7 +75,7 @@ pub async fn load_session_or_fallback( let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng); let ctx = AccountInactiveContext::new(session.user) .with_csrf(csrf_token.form_value()) - .with_language(locale.clone()); + .with_language(*locale); let fallback = templates.render_account_deactivated(&ctx)?; let response = (cookie_jar, Html(fallback)).into_response(); return Ok(SessionOrFallback::Fallback { response }); @@ -86,7 +86,7 @@ pub async fn load_session_or_fallback( let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng); let ctx = AccountInactiveContext::new(session.user) .with_csrf(csrf_token.form_value()) - .with_language(locale.clone()); + .with_language(*locale); let fallback = templates.render_account_locked(&ctx)?; let response = (cookie_jar, Html(fallback)).into_response(); return Ok(SessionOrFallback::Fallback { response }); @@ -100,7 +100,7 @@ pub async fn load_session_or_fallback( let (csrf_token, cookie_jar) = cookie_jar.csrf_token(clock, rng); let ctx = AccountInactiveContext::new(session.user) .with_csrf(csrf_token.form_value()) - .with_language(locale.clone()); + .with_language(*locale); let fallback = templates.render_account_logged_out(&ctx)?; let response = (cookie_jar, Html(fallback)).into_response(); return Ok(SessionOrFallback::Fallback { response }); diff --git a/crates/i18n/Cargo.toml b/crates/i18n/Cargo.toml index 8d04dc731..b81c3de4d 100644 --- a/crates/i18n/Cargo.toml +++ b/crates/i18n/Cargo.toml @@ -18,13 +18,11 @@ workspace = true [dependencies] camino.workspace = true -icu_calendar.workspace = true icu_datetime.workspace = true icu_experimental.workspace = true -icu_locid_transform.workspace = true -icu_locid.workspace = true +icu_locale.workspace = true +icu_locale_core.workspace = true icu_plurals.workspace = true -icu_provider_adapters.workspace = true icu_provider.workspace = true pad.workspace = true pest_derive.workspace = true diff --git a/crates/i18n/src/lib.rs b/crates/i18n/src/lib.rs index a4dfc7e2a..2f088af28 100644 --- a/crates/i18n/src/lib.rs +++ b/crates/i18n/src/lib.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2023, 2024 The Matrix.org Foundation C.I.C. // @@ -8,9 +9,8 @@ pub mod sprintf; pub mod translations; mod translator; -pub use icu_calendar; pub use icu_datetime; -pub use icu_locid::locale; +pub use icu_locale_core::{ParseError, locale}; pub use icu_provider::{DataError, DataLocale}; pub use self::{ diff --git a/crates/i18n/src/translator.rs b/crates/i18n/src/translator.rs index cd36a6c4b..9ef8d58e7 100644 --- a/crates/i18n/src/translator.rs +++ b/crates/i18n/src/translator.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2023, 2024 The Matrix.org Foundation C.I.C. // @@ -10,38 +11,15 @@ use camino::{Utf8Path, Utf8PathBuf}; use icu_experimental::relativetime::{ RelativeTimeFormatter, RelativeTimeFormatterOptions, options::Numeric, }; -use icu_locid::{Locale, ParserError}; -use icu_locid_transform::fallback::{ - LocaleFallbackPriority, LocaleFallbackSupplement, LocaleFallbacker, LocaleFallbackerWithConfig, -}; -use icu_plurals::{PluralRules, PluralsError}; -use icu_provider::{ - DataError, DataErrorKind, DataKey, DataLocale, DataRequest, DataRequestMetadata, data_key, - fallback::LocaleFallbackConfig, -}; -use icu_provider_adapters::fallback::LocaleFallbackProvider; +use icu_locale::fallback::{LocaleFallbackConfig, LocaleFallbacker}; +use icu_locale_core::{Locale, ParseError}; +use icu_plurals::PluralRules; +use icu_provider::{DataError, DataErrorKind, DataLocale}; use thiserror::Error; use writeable::Writeable; use crate::{sprintf::Message, translations::TranslationTree}; -/// Fake data key for errors -const DATA_KEY: DataKey = data_key!("mas/translations@1"); - -const FALLBACKER: LocaleFallbackerWithConfig<'static> = LocaleFallbacker::new().for_config({ - let mut config = LocaleFallbackConfig::const_default(); - config.priority = LocaleFallbackPriority::Collation; - config.fallback_supplement = Some(LocaleFallbackSupplement::Collation); - config -}); - -/// Construct a [`DataRequest`] for the given locale -pub fn data_request_for_locale(locale: &DataLocale) -> DataRequest<'_> { - let mut metadata = DataRequestMetadata::default(); - metadata.silent = true; - DataRequest { locale, metadata } -} - /// Error type for loading translations #[derive(Debug, Error)] pub enum LoadError { @@ -70,7 +48,7 @@ pub enum LoadError { InvalidLocale { path: Utf8PathBuf, #[source] - source: ParserError, + source: ParseError, }, #[error("Invalid file name {path:?}")] @@ -81,7 +59,7 @@ pub enum LoadError { #[derive(Debug)] pub struct Translator { translations: HashMap, - plural_provider: LocaleFallbackProvider, + fallbacker: LocaleFallbacker, default_locale: DataLocale, } @@ -90,16 +68,12 @@ impl Translator { #[must_use] pub fn new(translations: HashMap) -> Self { let fallbacker = LocaleFallbacker::new().static_to_owned(); - let plural_provider = LocaleFallbackProvider::new_with_fallbacker( - icu_plurals::provider::Baked, - fallbacker.clone(), - ); Self { translations, - plural_provider, + fallbacker, // TODO: make this configurable - default_locale: icu_locid::locale!("en").into(), + default_locale: icu_locale_core::locale!("en").into(), } } @@ -176,7 +150,10 @@ impl Translator { return Some((message, locale)); } - let mut iter = FALLBACKER.fallback_for(locale); + let mut iter = self + .fallbacker + .for_config(LocaleFallbackConfig::default()) + .fallback_for(locale); loop { let locale = iter.get(); @@ -186,9 +163,9 @@ impl Translator { } // Try the defaut locale if we hit the `und` locale - if locale.is_und() { + if locale.is_unknown() { let message = self.message(&self.default_locale, key).ok()?; - return Some((message, self.default_locale.clone())); + return Some((message, self.default_locale)); } iter.step(); @@ -207,16 +184,14 @@ impl Translator { /// Returns an error if the requested locale is not found, or if the /// requested key is not found. pub fn message(&self, locale: &DataLocale, key: &str) -> Result<&Message, DataError> { - let request = data_request_for_locale(locale); - let tree = self .translations .get(locale) - .ok_or_else(|| DataErrorKind::MissingLocale.with_req(DATA_KEY, request))?; + .ok_or_else(|| DataErrorKind::IdentifierNotFound.into_error())?; let message = tree .message(key) - .ok_or_else(|| DataErrorKind::MissingDataKey.with_req(DATA_KEY, request))?; + .ok_or_else(|| DataErrorKind::MarkerNotFound.into_error())?; Ok(message) } @@ -238,7 +213,10 @@ impl Translator { key: &str, count: usize, ) -> Option<(&Message, DataLocale)> { - let mut iter = FALLBACKER.fallback_for(locale); + let mut iter = self + .fallbacker + .for_config(LocaleFallbackConfig::default()) + .fallback_for(locale); loop { let locale = iter.get(); @@ -248,7 +226,7 @@ impl Translator { } // Stop if we hit the `und` locale - if locale.is_und() { + if locale.is_unknown() { return None; } @@ -273,20 +251,18 @@ impl Translator { locale: &DataLocale, key: &str, count: usize, - ) -> Result<&Message, PluralsError> { - let plurals = PluralRules::try_new_cardinal_unstable(&self.plural_provider, locale)?; + ) -> Result<&Message, DataError> { + let plurals = PluralRules::try_new_cardinal(locale.into_locale().into())?; let category = plurals.category_for(count); - let request = data_request_for_locale(locale); - let tree = self .translations .get(locale) - .ok_or_else(|| DataErrorKind::MissingLocale.with_req(DATA_KEY, request))?; + .ok_or_else(|| DataErrorKind::IdentifierNotFound.into_error())?; let message = tree .pluralize(key, category) - .ok_or_else(|| DataErrorKind::MissingDataKey.with_req(DATA_KEY, request))?; + .ok_or_else(|| DataErrorKind::MarkerNotFound.into_error())?; Ok(message) } @@ -302,18 +278,13 @@ impl Translator { /// # Errors /// /// Returns an error if the requested locale is not found. - pub fn relative_date( - &self, - locale: &DataLocale, - days: i64, - ) -> Result { + pub fn relative_date(&self, locale: &DataLocale, days: i64) -> Result { + let mut options = RelativeTimeFormatterOptions::default(); + options.numeric = Numeric::Auto; + // TODO: this is not using the fallbacker - let formatter = RelativeTimeFormatter::try_new_long_day( - locale, - RelativeTimeFormatterOptions { - numeric: Numeric::Auto, - }, - )?; + let formatter = + RelativeTimeFormatter::try_new_long_day(locale.into_locale().into(), options)?; let date = formatter.format(days.into()); Ok(date.write_to_string().into_owned()) @@ -329,24 +300,24 @@ impl Translator { /// # Errors /// /// Returns an error if the requested locale is not found. - pub fn short_time( + pub fn short_time( &self, locale: &DataLocale, - time: &T, - ) -> Result { + time: &icu_datetime::input::Time, + ) -> Result { // TODO: this is not using the fallbacker - let formatter = icu_datetime::TimeFormatter::try_new_with_length( - locale, - icu_datetime::options::length::Time::Short, + let formatter = icu_datetime::NoCalendarFormatter::try_new( + locale.into_locale().into(), + icu_datetime::fieldsets::T::short(), )?; - Ok(formatter.format_to_string(time)) + Ok(formatter.format(time).to_string()) } /// Get a list of available locales. #[must_use] pub fn available_locales(&self) -> Vec { - self.translations.keys().cloned().collect() + self.translations.keys().copied().collect() } /// Check if a locale is available. @@ -363,10 +334,13 @@ impl Translator { return locale; } - let mut fallbacker = FALLBACKER.fallback_for(locale); + let mut fallbacker = self + .fallbacker + .for_config(LocaleFallbackConfig::default()) + .fallback_for(locale); loop { - if fallbacker.get().is_und() { + if fallbacker.get().is_unknown() { break; } @@ -377,14 +351,14 @@ impl Translator { } } - self.default_locale.clone() + self.default_locale } } #[cfg(test)] mod tests { use camino::Utf8PathBuf; - use icu_locid::locale; + use icu_locale_core::locale; use crate::{sprintf::arg_list, translator::Translator}; diff --git a/crates/tasks/src/recovery.rs b/crates/tasks/src/recovery.rs index 51afcc295..0b3af373a 100644 --- a/crates/tasks/src/recovery.rs +++ b/crates/tasks/src/recovery.rs @@ -1,3 +1,4 @@ +// Copyright 2025, 2026 Element Creations Ltd. // Copyright 2024, 2025 New Vector Ltd. // Copyright 2024 The Matrix.org Foundation C.I.C. // @@ -93,8 +94,8 @@ impl RunnableJob for SendAccountRecoveryEmailsJob { let mailbox = Mailbox::new(Some(user.username.clone()), address); info!("Sending recovery email to {}", mailbox); - let context = EmailRecoveryContext::new(user, session.clone(), url) - .with_language(lang.clone()); + let context = + EmailRecoveryContext::new(user, session.clone(), url).with_language(lang); // XXX: we only log if the email fails to send, to avoid stopping the loop if let Err(e) = mailer.send_recovery_email(mailbox, &context).await { diff --git a/crates/templates/src/functions.rs b/crates/templates/src/functions.rs index adc4d4a87..ea47be14d 100644 --- a/crates/templates/src/functions.rs +++ b/crates/templates/src/functions.rs @@ -277,14 +277,14 @@ impl Object for TranslateFunc { let (message, _locale) = if let Some(count) = kwargs.get("count")? { self.translator - .plural_with_fallback(self.lang.clone(), key, count) + .plural_with_fallback(self.lang, key, count) .ok_or(Error::new( ErrorKind::InvalidOperation, "Missing translation", ))? } else { self.translator - .message_with_fallback(self.lang.clone(), key) + .message_with_fallback(self.lang, key) .ok_or(Error::new( ErrorKind::InvalidOperation, "Missing translation", @@ -363,6 +363,8 @@ impl Object for TranslateFunc { } "short_time" => { + use chrono::Timelike as _; + let (date,): (String,) = from_args(args)?; let date: chrono::DateTime = date.parse().map_err(|e| { Error::new( @@ -375,9 +377,20 @@ impl Object for TranslateFunc { // TODO: we should use the user's timezone here let time = date.time(); + // The hour, minute and second always fit in a `u8`. + let time = mas_i18n::icu_datetime::input::Time::try_new( + time.hour().try_into().unwrap_or(0), + time.minute().try_into().unwrap_or(0), + time.second().try_into().unwrap_or(0), + time.nanosecond(), + ) + .map_err(|e| { + Error::new(ErrorKind::InvalidOperation, "Invalid time").with_source(e) + })?; + Ok(Value::from( self.translator - .short_time(&self.lang, &TimeAdapter(time)) + .short_time(&self.lang, &time) .map_err(|_e| { Error::new(ErrorKind::InvalidOperation, "Failed to format time") })?, @@ -392,34 +405,6 @@ impl Object for TranslateFunc { } } -/// An adapter to make a [`Timelike`] implement [`IsoTimeInput`] -/// -/// [`Timelike`]: chrono::Timelike -/// [`IsoTimeInput`]: mas_i18n::icu_datetime::input::IsoTimeInput -struct TimeAdapter(T); - -impl mas_i18n::icu_datetime::input::IsoTimeInput for TimeAdapter { - fn hour(&self) -> Option { - let hour: usize = chrono::Timelike::hour(&self.0).try_into().ok()?; - hour.try_into().ok() - } - - fn minute(&self) -> Option { - let minute: usize = chrono::Timelike::minute(&self.0).try_into().ok()?; - minute.try_into().ok() - } - - fn second(&self) -> Option { - let second: usize = chrono::Timelike::second(&self.0).try_into().ok()?; - second.try_into().ok() - } - - fn nanosecond(&self) -> Option { - let nanosecond: usize = chrono::Timelike::nanosecond(&self.0).try_into().ok()?; - nanosecond.try_into().ok() - } -} - #[derive(Default, Debug)] struct IncludedAssetsTrackerInner { preloaded: HashSet,