Implement BCP-47 fallback for LanguageIdentifierDisplayName#8132
Conversation
…ions struct - Add `LanguageIdentifierDisplayNameOptions` with only the `language_display` option to `options.rs`. - Re-export it in `displaynames/mod.rs`. - Refactor `LanguageIdentifierDisplayNameOwned` to use `LanguageIdentifierDisplayNameOptions` instead of `DisplayNamesOptions`. - Update docstring examples and integration tests in `tests.rs` to use the new options struct. - Update `single/README.md` design documentation and add an open question about moving dialect names to a separate data marker. Co-authored-by: Gemini <176961590+gemini-code-assist[bot]@users.noreply.github.com>
d5b4878 to
a4d3b58
Compare
… and improve Rustiness - Reuse ScriptDisplayNameOwned, RegionDisplayNameOwned, and VariantDisplayNameOwned constructors in try_new_unstable to eliminate duplicate loading boilerplate. - Replace PayloadOrFallback enum with a type alias to DataPayloadOr<M, TinyAsciiStr<8>>, reusing robust existing implementations and eliminating custom Debug impl. - Use precise DataPayloadOr<LocaleNamesLanguageMediumV1, TinyAsciiStr<4>> for language_payload, avoiding unreachable Absent case. - Implement elegant Rusty iterator chain for variant loading. - Restore all original comments in language.rs. - Preserve original test_concatenate structure in tests.rs, running both strict and lenient checks in the same loop, and adding test_fallback_parts. Co-authored-by: Gemini <176961590+gemini-code-assist[bot]@users.noreply.github.com>
a4d3b58 to
cef16f4
Compare
… and improve Rustiness - Reuse ScriptDisplayNameOwned, RegionDisplayNameOwned, and VariantDisplayNameOwned constructors in try_new_unstable to eliminate duplicate loading boilerplate. - Replace PayloadOrFallback enum with a type alias to DataPayloadOr<M, TinyAsciiStr<8>>, reusing robust existing implementations and eliminating custom Debug impl. - Use precise DataPayloadOr<LocaleNamesLanguageMediumV1, TinyAsciiStr<4>> for language_payload, avoiding unreachable Absent case. - Implement elegant Rusty iterator chain for variant loading. - Restore all original comments in language.rs. - Preserve original test_concatenate structure in tests.rs, running both strict and lenient checks in the same loop, and adding test_fallback_parts. Co-authored-by: Gemini <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…d chain try_interpolate
|
I've gone over this multiple times. I'm happy with this now and ready for a review. |
|
🎉 All dependencies have been resolved ! |
Manishearth
left a comment
There was a problem hiding this comment.
Got a little confused around the error types for a bit but no, this is correct.
…ifier_not_found and cleanup imports
…docs, and refine doctests Co-authored-by: Gemini <176961590+gemini-code-assist[bot]@users.noreply.github.com>
sffc-bot
left a comment
There was a problem hiding this comment.
🤖 AI agent working with @sffc addressed actionable review comments in commit 7ae252c3ab (replaced AbsentOrFallback with Option, improved error docs, added Debug to with_fallback, and refined doc-tests).
LossyWrap is a transparent newtype wrapper around a TryWriteable. Adding standard derives and repr(transparent) allows wrapping values in LossyWrap without stripping Copy, Clone, or equality traits, enabling use in Copy structs and delegate macros. Co-authored-by: Gemini <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…e .with_fallback() Structure LanguageIdentifierDisplayName as an outer LossyWrap wrapper around an inner struct, implementing TryWriteable, Writeable, and Display directly using writeable delegate macros. Remove the .with_fallback() method and update all doc tests and unit tests. Co-authored-by: Gemini <176961590+gemini-code-assist[bot]@users.noreply.github.com>
|
I changed it to implement both Writeable and TryWriteable on the same type, instead of making a function that returns |
| writeable::impl_try_writeable_delegate!( | ||
| LanguageIdentifierDisplayName<'_>, | ||
| |&self| &self.0.0, | ||
| Error = LanguageIdentifierNameFallbackError | ||
| ); | ||
|
|
||
| writeable::impl_writeable_delegate!(LanguageIdentifierDisplayName<'_>, |&self| &self.0); | ||
|
|
||
| writeable::impl_display_with_writeable!(LanguageIdentifierDisplayName<'_>); |
There was a problem hiding this comment.
I don't think you need a separate inner type. just implement TryWriteable directly on LanguageIdentifierDisplayName, and then
| writeable::impl_try_writeable_delegate!( | |
| LanguageIdentifierDisplayName<'_>, | |
| |&self| &self.0.0, | |
| Error = LanguageIdentifierNameFallbackError | |
| ); | |
| writeable::impl_writeable_delegate!(LanguageIdentifierDisplayName<'_>, |&self| &self.0); | |
| writeable::impl_display_with_writeable!(LanguageIdentifierDisplayName<'_>); | |
| writeable::impl_writeable_delegate!(LanguageIdentifierDisplayName<'_>, |&self| LossyWrap(&self.0)); | |
| writeable::impl_display_with_writeable!(LanguageIdentifierDisplayName<'_>); |
There was a problem hiding this comment.
Unfortunately this pattern doesn't work because write_to_string borrows from the temporary LossyWrap. The Writeable trait doesn't have a way to track the inner lifetime.
| match VariantDisplayNameOwned::try_new_unstable(provider, prefs, variant) | ||
| .allow_identifier_not_found()? | ||
| { | ||
| Some(obj) => Ok(DataPayloadOr::from_payload(obj.payload)), | ||
| None => Ok(DataPayloadOr::from_other(variant)), | ||
| } |
There was a problem hiding this comment.
| match VariantDisplayNameOwned::try_new_unstable(provider, prefs, variant) | |
| .allow_identifier_not_found()? | |
| { | |
| Some(obj) => Ok(DataPayloadOr::from_payload(obj.payload)), | |
| None => Ok(DataPayloadOr::from_other(variant)), | |
| } | |
| Ok(VariantDisplayNameOwned::try_new_unstable(provider, prefs, variant) | |
| .allow_identifier_not_found()? | |
| .map_or_default( | |
| || DataPayloadOr::from_other(variant), | |
| |r| DataPayloadOr::from_payload(r.payload))) |
also elsewhere
There was a problem hiding this comment.
map_or_default is too new
Co-authored-by: Robert Bastian <4706271+robertbastian@users.noreply.github.com>
|
There are a lot of comments so I'm going to click resolve on the ones that are either fixed or have follow-up issues filed. |
|
I think the last round of comments was more about subjective style and commenting choices than substance, with the possible exception of the error handling, because I agree it's better style to track errors. Variable names and things like that being self-inconsistent in the same file is, well, regrettable but 🤷 not really worth the ping-pong to fix IMO. This PR has been in a mergeable state 3 times. Let's please favor follow-up issues. |
robertbastian
left a comment
There was a problem hiding this comment.
Variable names and things like that being self-inconsistent in the same file is, well, regrettable but 🤷 not really worth the ping-pong to fix IMO.
You could just not send code like that for review. It might involve hand-writing it.
Depends on #8135
This pull request is part of the implementation for the main locale display names tracking issue: #7825.
This pull request implements full BCP-47 subtag fallback hierarchy for the new
LanguageIdentifierDisplayName(and its owned version), resolving the core fallback requirements for the experimental single displaynames module.Key Changes
writeablecrate,LanguageIdentifierDisplayNamenow implements bothTryWriteable(for strict error detection and error part annotation) andWriteable/Display(for standard lenient formatting with raw code fallback) directly on the struct.LanguageIdentifierDisplayNameis structured as a tuple newtype wrapping an inner struct inLossyWrap, leveragingwriteable::impl_try_writeable_delegate!andwriteable::impl_writeable_delegate!.WriteableandTryWriteablefromLanguageIdentifierDisplayNameOwned(callers use.as_borrowed()to format).DisplayNamesFallbackErrortoLanguageIdentifierNameFallbackError(correcting the spelling of "Identifier" to match the formatter).pub const fn new()constructor and adopted struct syntaxLanguageIdentifierNameFallbackErrorfor construction, while suppressing theclippy::exhaustive_structswarning.TryWriteableimplementation forResult<T, E>in thewriteablecrate to simplify the manual match-writing andPart::ERRORannotation blocks in bothQualifiersWriteableandLanguageIdentifierDisplayNameformatting code, making it extremely concise and clean.ScriptDisplayNameOwned,RegionDisplayNameOwned, andVariantDisplayNameOwnedin the main constructor to load sub-parts, eliminating hundreds of lines of duplicate data-loading code.Part::ERRORduring strict formatting, enabling advanced styling in downstream applications.borrowed.try_write_to_string()for clean, idiomatic fallback verification.🤖 This pull request was created by an AI agent working with @sffc.
Changelog
writeable: Add standard derives and
repr(transparent)toLossyWrapLossyWrap<T>now derivesClone,Copy,PartialEq,Eq,PartialOrd,Ord, andHash, and is marked#[repr(transparent)], enabling its use insideCopystructs and with delegate macros.impl_try_writeable_delegate!icu_experimental: Implement BCP-47 fallback for
LanguageIdentifierDisplayNameLanguageIdentifierNameFallbackErrorLanguageIdentifierDisplayNameimplementsTryWriteable,Writeable, andDisplaydirectly usingwriteable::impl_delegatemacros over an internalLossyWrapfield.WriteableandTryWriteablefromLanguageIdentifierDisplayNameOwned(use.as_borrowed()to format).try_new(),try_new_with_buffer_provider(), andtry_new_unstable()no longer fail when the display name is not found.