diff options
Diffstat (limited to 'third_party/rust/fluent-bundle/src/message.rs')
-rw-r--r-- | third_party/rust/fluent-bundle/src/message.rs | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/third_party/rust/fluent-bundle/src/message.rs b/third_party/rust/fluent-bundle/src/message.rs new file mode 100644 index 0000000000..a6cc00d77e --- /dev/null +++ b/third_party/rust/fluent-bundle/src/message.rs @@ -0,0 +1,274 @@ +use fluent_syntax::ast; + +/// [`FluentAttribute`] is a component of a compound [`FluentMessage`]. +/// +/// It represents a key-value pair providing a translation of a component +/// of a user interface widget localized by the given message. +/// +/// # Example +/// +/// ``` +/// use fluent_bundle::{FluentResource, FluentBundle}; +/// +/// let source = r#" +/// +/// confirm-modal = Are you sure? +/// .confirm = Yes +/// .cancel = No +/// .tooltip = Closing the window will lose all unsaved data. +/// +/// "#; +/// +/// let resource = FluentResource::try_new(source.to_string()) +/// .expect("Failed to parse the resource."); +/// +/// let mut bundle = FluentBundle::default(); +/// bundle.add_resource(resource) +/// .expect("Failed to add a resource."); +/// +/// let msg = bundle.get_message("confirm-modal") +/// .expect("Failed to retrieve a message."); +/// +/// let mut err = vec![]; +/// +/// let attributes = msg.attributes().map(|attr| { +/// bundle.format_pattern(attr.value(), None, &mut err) +/// }).collect::<Vec<_>>(); +/// +/// assert_eq!(attributes[0], "Yes"); +/// assert_eq!(attributes[1], "No"); +/// assert_eq!(attributes[2], "Closing the window will lose all unsaved data."); +/// ``` +#[derive(Debug, PartialEq)] +pub struct FluentAttribute<'m> { + node: &'m ast::Attribute<&'m str>, +} + +impl<'m> FluentAttribute<'m> { + /// Retrieves an id of an attribute. + /// + /// # Example + /// + /// ``` + /// # use fluent_bundle::{FluentResource, FluentBundle}; + /// # let source = r#" + /// # confirm-modal = + /// # .confirm = Yes + /// # "#; + /// # let resource = FluentResource::try_new(source.to_string()) + /// # .expect("Failed to parse the resource."); + /// # let mut bundle = FluentBundle::default(); + /// # bundle.add_resource(resource) + /// # .expect("Failed to add a resource."); + /// let msg = bundle.get_message("confirm-modal") + /// .expect("Failed to retrieve a message."); + /// + /// let attr1 = msg.attributes().next() + /// .expect("Failed to retrieve an attribute."); + /// + /// assert_eq!(attr1.id(), "confirm"); + /// ``` + pub fn id(&self) -> &'m str { + &self.node.id.name + } + + /// Retrieves an value of an attribute. + /// + /// # Example + /// + /// ``` + /// # use fluent_bundle::{FluentResource, FluentBundle}; + /// # let source = r#" + /// # confirm-modal = + /// # .confirm = Yes + /// # "#; + /// # let resource = FluentResource::try_new(source.to_string()) + /// # .expect("Failed to parse the resource."); + /// # let mut bundle = FluentBundle::default(); + /// # bundle.add_resource(resource) + /// # .expect("Failed to add a resource."); + /// let msg = bundle.get_message("confirm-modal") + /// .expect("Failed to retrieve a message."); + /// + /// let attr1 = msg.attributes().next() + /// .expect("Failed to retrieve an attribute."); + /// + /// let mut err = vec![]; + /// + /// let value = attr1.value(); + /// assert_eq!( + /// bundle.format_pattern(value, None, &mut err), + /// "Yes" + /// ); + /// ``` + pub fn value(&self) -> &'m ast::Pattern<&'m str> { + &self.node.value + } +} + +impl<'m> From<&'m ast::Attribute<&'m str>> for FluentAttribute<'m> { + fn from(attr: &'m ast::Attribute<&'m str>) -> Self { + FluentAttribute { node: attr } + } +} + +/// [`FluentMessage`] is a basic translation unit of the Fluent system. +/// +/// The instance of a message is returned from the +/// [`FluentBundle::get_message`](crate::bundle::FluentBundle::get_message) +/// method, for the lifetime of the [`FluentBundle`](crate::bundle::FluentBundle) instance. +/// +/// # Example +/// +/// ``` +/// use fluent_bundle::{FluentResource, FluentBundle}; +/// +/// let source = r#" +/// +/// hello-world = Hello World! +/// +/// "#; +/// +/// let resource = FluentResource::try_new(source.to_string()) +/// .expect("Failed to parse the resource."); +/// +/// let mut bundle = FluentBundle::default(); +/// bundle.add_resource(resource) +/// .expect("Failed to add a resource."); +/// +/// let msg = bundle.get_message("hello-world") +/// .expect("Failed to retrieve a message."); +/// +/// assert!(msg.value().is_some()); +/// ``` +/// +/// That value can be then passed to +/// [`FluentBundle::format_pattern`](crate::bundle::FluentBundle::format_pattern) to be formatted +/// within the context of a given [`FluentBundle`](crate::bundle::FluentBundle) instance. +/// +/// # Compound Message +/// +/// A message may contain a `value`, but it can also contain a list of [`FluentAttribute`] elements. +/// +/// If a message contains attributes, it is called a "compound" message. +/// +/// In such case, the message contains a list of key-value attributes that represent +/// different translation values associated with a single translation unit. +/// +/// This is useful for scenarios where a [`FluentMessage`] is associated with a +/// complex User Interface widget which has multiple attributes that need to be translated. +/// ```text +/// confirm-modal = Are you sure? +/// .confirm = Yes +/// .cancel = No +/// .tooltip = Closing the window will lose all unsaved data. +/// ``` +#[derive(Debug, PartialEq)] +pub struct FluentMessage<'m> { + node: &'m ast::Message<&'m str>, +} + +impl<'m> FluentMessage<'m> { + /// Retrieves an option of a [`ast::Pattern`](fluent_syntax::ast::Pattern). + /// + /// # Example + /// + /// ``` + /// # use fluent_bundle::{FluentResource, FluentBundle}; + /// # let source = r#" + /// # hello-world = Hello World! + /// # "#; + /// # let resource = FluentResource::try_new(source.to_string()) + /// # .expect("Failed to parse the resource."); + /// # let mut bundle = FluentBundle::default(); + /// # bundle.add_resource(resource) + /// # .expect("Failed to add a resource."); + /// let msg = bundle.get_message("hello-world") + /// .expect("Failed to retrieve a message."); + /// + /// if let Some(value) = msg.value() { + /// let mut err = vec![]; + /// assert_eq!( + /// bundle.format_pattern(value, None, &mut err), + /// "Hello World!" + /// ); + /// # assert_eq!(err.len(), 0); + /// } + /// ``` + pub fn value(&self) -> Option<&'m ast::Pattern<&'m str>> { + self.node.value.as_ref() + } + + /// An iterator over [`FluentAttribute`] elements. + /// + /// # Example + /// + /// ``` + /// # use fluent_bundle::{FluentResource, FluentBundle}; + /// # let source = r#" + /// # hello-world = + /// # .label = This is a label + /// # .accesskey = C + /// # "#; + /// # let resource = FluentResource::try_new(source.to_string()) + /// # .expect("Failed to parse the resource."); + /// # let mut bundle = FluentBundle::default(); + /// # bundle.add_resource(resource) + /// # .expect("Failed to add a resource."); + /// let msg = bundle.get_message("hello-world") + /// .expect("Failed to retrieve a message."); + /// + /// let mut err = vec![]; + /// + /// for attr in msg.attributes() { + /// let _ = bundle.format_pattern(attr.value(), None, &mut err); + /// } + /// # assert_eq!(err.len(), 0); + /// ``` + pub fn attributes(&self) -> impl Iterator<Item = FluentAttribute<'m>> { + self.node.attributes.iter().map(Into::into) + } + + /// Retrieve a single [`FluentAttribute`] element. + /// + /// # Example + /// + /// ``` + /// # use fluent_bundle::{FluentResource, FluentBundle}; + /// # let source = r#" + /// # hello-world = + /// # .label = This is a label + /// # .accesskey = C + /// # "#; + /// # let resource = FluentResource::try_new(source.to_string()) + /// # .expect("Failed to parse the resource."); + /// # let mut bundle = FluentBundle::default(); + /// # bundle.add_resource(resource) + /// # .expect("Failed to add a resource."); + /// let msg = bundle.get_message("hello-world") + /// .expect("Failed to retrieve a message."); + /// + /// let mut err = vec![]; + /// + /// if let Some(attr) = msg.get_attribute("label") { + /// assert_eq!( + /// bundle.format_pattern(attr.value(), None, &mut err), + /// "This is a label" + /// ); + /// } + /// # assert_eq!(err.len(), 0); + /// ``` + pub fn get_attribute(&self, key: &str) -> Option<FluentAttribute<'m>> { + self.node + .attributes + .iter() + .find(|attr| attr.id.name == key) + .map(Into::into) + } +} + +impl<'m> From<&'m ast::Message<&'m str>> for FluentMessage<'m> { + fn from(msg: &'m ast::Message<&'m str>) -> Self { + FluentMessage { node: msg } + } +} |