//! Abstract Syntax Tree representation of the Fluent Translation List. //! //! The AST of Fluent contains all nodes structures to represent a complete //! representation of the FTL resource. //! //! The tree preserves all semantic information and allow for round-trip //! of a canonically written FTL resource. //! //! The root node is called [`Resource`] and contains a list of [`Entry`] nodes //! representing all possible entries in the Fluent Translation List. //! //! # Example //! //! ``` //! use fluent_syntax::parser; //! use fluent_syntax::ast; //! //! let ftl = r#" //! //! ## This is a message comment //! hello-world = Hello World! //! .tooltip = Tooltip for you, { $userName }. //! //! "#; //! //! let resource = parser::parse(ftl) //! .expect("Failed to parse an FTL resource."); //! //! assert_eq!( //! resource.body[0], //! ast::Entry::Message( //! ast::Message { //! id: ast::Identifier { //! name: "hello-world" //! }, //! value: Some(ast::Pattern { //! elements: vec![ //! ast::PatternElement::TextElement { //! value: "Hello World!" //! }, //! ] //! }), //! attributes: vec![ //! ast::Attribute { //! id: ast::Identifier { //! name: "tooltip" //! }, //! value: ast::Pattern { //! elements: vec![ //! ast::PatternElement::TextElement { //! value: "Tooltip for you, " //! }, //! ast::PatternElement::Placeable { //! expression: ast::Expression::Inline( //! ast::InlineExpression::VariableReference { //! id: ast::Identifier { //! name: "userName" //! } //! } //! ) //! }, //! ast::PatternElement::TextElement { //! value: "." //! }, //! ] //! } //! } //! ], //! comment: Some( //! ast::Comment { //! content: vec!["This is a message comment"] //! } //! ) //! } //! ), //! ); //! ``` //! //! ## Errors //! //! Fluent AST preserves blocks containing invaid syntax as [`Entry::Junk`]. //! //! ## White space //! //! At the moment, AST does not preserve white space. In result only a //! canonical form of the AST is suitable for a round-trip. mod helper;
#[cfg(feature = "serde")] use serde::{Deserialize, Serialize};
/// Root node of a Fluent Translation List. /// /// A [`Resource`] contains a body with a list of [`Entry`] nodes. /// /// # Example /// /// ``` /// use fluent_syntax::parser; /// use fluent_syntax::ast; /// /// let ftl = ""; /// /// let resource = parser::parse(ftl) /// .expect("Failed to parse an FTL resource."); /// /// assert_eq!( /// resource, /// ast::Resource { /// body: vec![] /// } /// ); /// ``` #[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pubstruct Resource<S> { pub body: Vec<Entry<S>>,
}
/// A top-level node representing an entry of a [`Resource`]. /// /// Every [`Entry`] is a standalone element and the parser is capable /// of recovering from errors by identifying a beginning of a next entry. /// /// # Example /// /// ``` /// use fluent_syntax::parser; /// use fluent_syntax::ast; /// /// let ftl = r#" /// /// key = Value /// /// "#; /// /// let resource = parser::parse(ftl) /// .expect("Failed to parse an FTL resource."); /// /// assert_eq!( /// resource, /// ast::Resource { /// body: vec![ /// ast::Entry::Message( /// ast::Message { /// id: ast::Identifier { /// name: "key" /// }, /// value: Some(ast::Pattern { /// elements: vec![ /// ast::PatternElement::TextElement { /// value: "Value" /// }, /// ] /// }), /// attributes: vec![], /// comment: None, /// } /// ) /// ] /// } /// ); /// ``` /// /// # Junk Entry /// /// If FTL source contains invalid FTL content, it will be preserved /// in form of [`Entry::Junk`] nodes. /// /// # Example /// /// ``` /// use fluent_syntax::parser; /// use fluent_syntax::ast; /// /// let ftl = r#" /// /// g@rb@ge En!ry /// /// "#; /// /// let (resource, _) = parser::parse(ftl) /// .expect_err("Failed to parse an FTL resource."); /// /// assert_eq!( /// resource, /// ast::Resource { /// body: vec![ /// ast::Entry::Junk { /// content: "g@rb@ge En!ry\n\n" /// } /// ] /// } /// ); /// ``` #[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(tag = "type"))] pubenum Entry<S> {
Message(Message<S>),
Term(Term<S>),
Comment(Comment<S>),
GroupComment(Comment<S>),
ResourceComment(Comment<S>),
Junk { content: S },
}
/// Message node represents the most common [`Entry`] in an FTL [`Resource`]. /// /// A message is a localization unit with a [`Identifier`] unique within a given /// [`Resource`], and a value or attributes with associated [`Pattern`]. /// /// A message can contain a simple text value, or a compound combination of value /// and attributes which together can be used to localize a complex User Interface /// element. /// /// Finally, each [`Message`] may have an associated [`Comment`]. /// /// # Example /// /// ``` /// use fluent_syntax::parser; /// use fluent_syntax::ast; /// /// let ftl = r#" /// /// hello-world = Hello, World! /// /// "#; /// /// let resource = parser::parse(ftl) /// .expect("Failed to parse an FTL resource."); /// /// assert_eq!( /// resource, /// ast::Resource { /// body: vec![ /// ast::Entry::Message(ast::Message { /// id: ast::Identifier { /// name: "hello-world" /// }, /// value: Some(ast::Pattern { /// elements: vec![ /// ast::PatternElement::TextElement { /// value: "Hello, World!" /// } /// ] /// }), /// attributes: vec![], /// comment: None, /// }) /// ] /// } /// ); /// ``` #[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pubstruct Message<S> { pub id: Identifier<S>, pub value: Option<Pattern<S>>, pub attributes: Vec<Attribute<S>>, pub comment: Option<Comment<S>>,
}
/// A Fluent [`Term`]. /// /// Terms are semantically similar to [`Message`] nodes, but /// they represent a separate concept in Fluent system. /// /// Every term has to have a value, and the parser will /// report errors when term references are used in wrong positions. /// /// # Example /// /// ``` /// use fluent_syntax::parser; /// use fluent_syntax::ast; /// /// let ftl = r#" /// /// -brand-name = Nightly /// /// "#; /// /// let resource = parser::parse(ftl) /// .expect("Failed to parse an FTL resource."); /// /// assert_eq!( /// resource, /// ast::Resource { /// body: vec![ /// ast::Entry::Term(ast::Term { /// id: ast::Identifier { /// name: "brand-name" /// }, /// value: ast::Pattern { /// elements: vec![ /// ast::PatternElement::TextElement { /// value: "Nightly" /// } /// ] /// }, /// attributes: vec![], /// comment: None, /// }) /// ] /// } /// ); /// ``` #[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pubstruct Term<S> { pub id: Identifier<S>, pub value: Pattern<S>, pub attributes: Vec<Attribute<S>>, pub comment: Option<Comment<S>>,
}
/// Pattern contains a value of a [`Message`], [`Term`] or an [`Attribute`]. /// /// Each pattern is a list of [`PatternElement`] nodes representing /// either a simple textual value, or a combination of text literals /// and placeholder [`Expression`] nodes. /// /// # Example /// /// ``` /// use fluent_syntax::parser; /// use fluent_syntax::ast; /// /// let ftl = r#" /// /// hello-world = Hello, World! /// /// welcome = Welcome, { $userName }. /// /// "#; /// /// let resource = parser::parse(ftl) /// .expect("Failed to parse an FTL resource."); /// /// assert_eq!( /// resource, /// ast::Resource { /// body: vec![ /// ast::Entry::Message(ast::Message { /// id: ast::Identifier { /// name: "hello-world" /// }, /// value: Some(ast::Pattern { /// elements: vec![ /// ast::PatternElement::TextElement { /// value: "Hello, World!" /// } /// ] /// }), /// attributes: vec![], /// comment: None, /// }), /// ast::Entry::Message(ast::Message { /// id: ast::Identifier { /// name: "welcome" /// }, /// value: Some(ast::Pattern { /// elements: vec![ /// ast::PatternElement::TextElement { /// value: "Welcome, " /// }, /// ast::PatternElement::Placeable { /// expression: ast::Expression::Inline( /// ast::InlineExpression::VariableReference { /// id: ast::Identifier { /// name: "userName" /// } /// } /// ) /// }, /// ast::PatternElement::TextElement { /// value: "." /// } /// ] /// }), /// attributes: vec![], /// comment: None, /// }), /// ] /// } /// ); /// ``` #[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pubstruct Pattern<S> { pub elements: Vec<PatternElement<S>>,
}
/// Fluent [`Comment`]. /// /// In Fluent, comments may be standalone, or associated with /// an entry such as [`Term`] or [`Message`]. /// /// When used as a standalone [`Entry`], comments may appear in one of /// three levels: /// /// * Standalone comment /// * Group comment associated with a group of messages /// * Resource comment associated with the whole resource /// /// # Example /// /// ``` /// use fluent_syntax::parser; /// use fluent_syntax::ast; /// /// let ftl = r#" /// ## A standalone level comment /// "#; /// /// let resource = parser::parse(ftl) /// .expect("Failed to parse an FTL resource."); /// /// assert_eq!( /// resource, /// ast::Resource { /// body: vec![ /// ast::Entry::Comment(ast::Comment { /// content: vec![ /// "A standalone level comment" /// ] /// }) /// ] /// } /// ); /// ``` #[derive(Debug, PartialEq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(from = "helper::CommentDef<S>"))] pubstruct Comment<S> { pub content: Vec<S>,
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.