| 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 | |