| 1 | //! Fluent is a modern localization system designed to improve how software is translated. | 
| 2 | //! | 
|---|
| 3 | //! `fluent-bundle` is a mid-level component of the [Fluent Localization | 
|---|
| 4 | //! System](https://www.projectfluent.org). | 
|---|
| 5 | //! | 
|---|
| 6 | //! The crate builds on top of the low level [`fluent-syntax`](https://crates.io/crates/fluent-syntax) package, and provides | 
|---|
| 7 | //! foundational types and structures required for executing localization at runtime. | 
|---|
| 8 | //! | 
|---|
| 9 | //! There are four core concepts to understand Fluent runtime: | 
|---|
| 10 | //! | 
|---|
| 11 | //! * [`FluentMessage`] - A single translation unit | 
|---|
| 12 | //! * [`FluentResource`] - A list of [`FluentMessage`] units | 
|---|
| 13 | //! * [`FluentBundle`](crate::bundle::FluentBundle) - A collection of [`FluentResource`] lists | 
|---|
| 14 | //! * [`FluentArgs`] - A list of elements used to resolve a [`FluentMessage`] value | 
|---|
| 15 | //! | 
|---|
| 16 | //! ## Example | 
|---|
| 17 | //! | 
|---|
| 18 | //! ``` | 
|---|
| 19 | //! use fluent_bundle::{FluentBundle, FluentValue, FluentResource, FluentArgs}; | 
|---|
| 20 | //! // Used to provide a locale for the bundle. | 
|---|
| 21 | //! use unic_langid::langid; | 
|---|
| 22 | //! | 
|---|
| 23 | //! // 1. Crate a FluentResource | 
|---|
| 24 | //! | 
|---|
| 25 | //! let ftl_string = r#" | 
|---|
| 26 | //! | 
|---|
| 27 | //! hello-world = Hello, world! | 
|---|
| 28 | //! intro = Welcome, { $name }. | 
|---|
| 29 | //! | 
|---|
| 30 | //! "#.to_string(); | 
|---|
| 31 | //! | 
|---|
| 32 | //! let res = FluentResource::try_new(ftl_string) | 
|---|
| 33 | //!     .expect( "Failed to parse an FTL string."); | 
|---|
| 34 | //! | 
|---|
| 35 | //! | 
|---|
| 36 | //! // 2. Crate a FluentBundle | 
|---|
| 37 | //! | 
|---|
| 38 | //! let langid_en = langid!( "en-US"); | 
|---|
| 39 | //! let mut bundle = FluentBundle::new(vec![langid_en]); | 
|---|
| 40 | //! | 
|---|
| 41 | //! | 
|---|
| 42 | //! // 3. Add the resource to the bundle | 
|---|
| 43 | //! | 
|---|
| 44 | //! bundle | 
|---|
| 45 | //!     .add_resource(res) | 
|---|
| 46 | //!     .expect( "Failed to add FTL resources to the bundle."); | 
|---|
| 47 | //! | 
|---|
| 48 | //! | 
|---|
| 49 | //! // 4. Retrieve a FluentMessage from the bundle | 
|---|
| 50 | //! | 
|---|
| 51 | //! let msg = bundle.get_message( "hello-world") | 
|---|
| 52 | //!     .expect( "Message doesn't exist."); | 
|---|
| 53 | //! | 
|---|
| 54 | //! | 
|---|
| 55 | //! // 5. Format the value of the simple message | 
|---|
| 56 | //! | 
|---|
| 57 | //! let mut errors = vec![]; | 
|---|
| 58 | //! | 
|---|
| 59 | //! let pattern = msg.value() | 
|---|
| 60 | //!     .expect( "Message has no value."); | 
|---|
| 61 | //! | 
|---|
| 62 | //! let value = bundle.format_pattern(&pattern, None, &mut errors); | 
|---|
| 63 | //! | 
|---|
| 64 | //! assert_eq!( | 
|---|
| 65 | //!     bundle.format_pattern(&pattern, None, &mut errors), | 
|---|
| 66 | //! "Hello, world!" | 
|---|
| 67 | //! ); | 
|---|
| 68 | //! | 
|---|
| 69 | //! // 6. Format the value of the message with arguments | 
|---|
| 70 | //! | 
|---|
| 71 | //! let mut args = FluentArgs::new(); | 
|---|
| 72 | //! args.set( "name", "John"); | 
|---|
| 73 | //! | 
|---|
| 74 | //! let msg = bundle.get_message( "intro") | 
|---|
| 75 | //!     .expect( "Message doesn't exist."); | 
|---|
| 76 | //! | 
|---|
| 77 | //! let pattern = msg.value() | 
|---|
| 78 | //!     .expect( "Message has no value."); | 
|---|
| 79 | //! | 
|---|
| 80 | //! // The FSI/PDI isolation marks ensure that the direction of | 
|---|
| 81 | //! // the text from the variable is not affected by the translation. | 
|---|
| 82 | //! assert_eq!( | 
|---|
| 83 | //!     bundle.format_pattern(&pattern, Some(&args), &mut errors), | 
|---|
| 84 | //! "Welcome, \u{2068} John\u{2069} ." | 
|---|
| 85 | //! ); | 
|---|
| 86 | //! ``` | 
|---|
| 87 | //! | 
|---|
| 88 | //! # Ergonomics & Higher Level APIs | 
|---|
| 89 | //! | 
|---|
| 90 | //! Reading the example, you may notice how verbose it feels. | 
|---|
| 91 | //! Many core methods are fallible, others accumulate errors, and there | 
|---|
| 92 | //! are intermediate structures used in operations. | 
|---|
| 93 | //! | 
|---|
| 94 | //! This is intentional as it serves as building blocks for variety of different | 
|---|
| 95 | //! scenarios allowing implementations to handle errors, cache and | 
|---|
| 96 | //! optimize results. | 
|---|
| 97 | //! | 
|---|
| 98 | //! At the moment it is expected that users will use | 
|---|
| 99 | //! the `fluent-bundle` crate directly, while the ecosystem | 
|---|
| 100 | //! matures and higher level APIs are being developed. | 
|---|
| 101 | mod args; | 
|---|
| 102 | pub mod bundle; | 
|---|
| 103 | pub mod concurrent; | 
|---|
| 104 | mod entry; | 
|---|
| 105 | mod errors; | 
|---|
| 106 | #[ doc(hidden)] | 
|---|
| 107 | pub mod memoizer; | 
|---|
| 108 | mod message; | 
|---|
| 109 | #[ doc(hidden)] | 
|---|
| 110 | pub mod resolver; | 
|---|
| 111 | mod resource; | 
|---|
| 112 | pub mod types; | 
|---|
| 113 |  | 
|---|
| 114 | pub use args::FluentArgs; | 
|---|
| 115 | /// Specialized [`FluentBundle`](crate::bundle::FluentBundle) over | 
|---|
| 116 | /// non-concurrent [`IntlLangMemoizer`](intl_memoizer::IntlLangMemoizer). | 
|---|
| 117 | /// | 
|---|
| 118 | /// This is the basic variant of the [`FluentBundle`](crate::bundle::FluentBundle). | 
|---|
| 119 | /// | 
|---|
| 120 | /// The concurrent specialization can be constructed with | 
|---|
| 121 | /// [`FluentBundle::new_concurrent`](crate::concurrent::FluentBundle::new_concurrent). | 
|---|
| 122 | pub type FluentBundle<R> = bundle::FluentBundle<R, intl_memoizer::IntlLangMemoizer>; | 
|---|
| 123 | pub use errors::FluentError; | 
|---|
| 124 | pub use message::{FluentAttribute, FluentMessage}; | 
|---|
| 125 | pub use resource::FluentResource; | 
|---|
| 126 | #[ doc(inline)] | 
|---|
| 127 | pub use types::FluentValue; | 
|---|
| 128 |  | 
|---|