Skip to main content

icu_provider/
hello_world.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! Data provider returning multilingual "Hello World" strings for testing.
6
7#![allow(clippy::exhaustive_structs)] // data struct module
8
9use crate as icu_provider;
10
11use crate::prelude::*;
12use alloc::borrow::Cow;
13use alloc::collections::BTreeSet;
14use alloc::string::String;
15use core::fmt::Debug;
16use icu_locale_core::preferences::define_preferences;
17use writeable::Writeable;
18use yoke::*;
19use zerofrom::*;
20
21/// A struct containing "Hello World" in the requested language.
22#[derive(Debug, PartialEq, Clone, Yokeable, ZeroFrom)]
23#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
24#[cfg_attr(
25    any(feature = "deserialize_json", feature = "export"),
26    derive(serde::Serialize)
27)]
28#[cfg_attr(feature = "export", derive(databake::Bake))]
29#[cfg_attr(feature = "export", databake(path = icu_provider::hello_world))]
30pub struct HelloWorld<'data> {
31    /// The translation of "Hello World".
32    #[cfg_attr(feature = "serde", serde(borrow))]
33    pub message: Cow<'data, str>,
34}
35
36impl Default for HelloWorld<'_> {
37    fn default() -> Self {
38        HelloWorld {
39            message: Cow::Borrowed("(und) Hello World"),
40        }
41    }
42}
43
44impl<'a> ZeroFrom<'a, str> for HelloWorld<'a> {
45    fn zero_from(message: &'a str) -> Self {
46        HelloWorld {
47            message: Cow::Borrowed(message),
48        }
49    }
50}
51
52crate::data_struct!(
53    HelloWorld<'data>,
54    varule: str,
55    #[cfg(feature = "export")]
56    encode_as_varule: |v: &HelloWorld<'_>| &*v.message
57);
58
59data_marker!(
60    /// Marker type for [`HelloWorld`].
61    #[derive(Debug)]
62    HelloWorldV1,
63    HelloWorld<'static>,
64    has_checksum = true,
65    #[cfg(feature = "export")]
66    attributes_domain = "hello",
67);
68
69/// A data provider returning Hello World strings in different languages.
70///
71/// Mostly useful for testing.
72///
73/// # Examples
74///
75/// ```
76/// use icu_locale_core::langid;
77/// use icu_provider::hello_world::*;
78/// use icu_provider::prelude::*;
79///
80/// let german_hello_world: DataResponse<HelloWorldV1> = HelloWorldProvider
81///     .load(DataRequest {
82///         id: DataIdentifierBorrowed::for_locale(&langid!("de").into()),
83///         ..Default::default()
84///     })
85///     .expect("Loading should succeed");
86///
87/// assert_eq!("Hallo Welt", german_hello_world.payload.get().message);
88/// ```
89///
90/// Load the reverse string using an auxiliary key:
91///
92/// ```
93/// use icu_locale_core::langid;
94/// use icu_provider::hello_world::*;
95/// use icu_provider::prelude::*;
96///
97/// let reverse_hello_world: DataResponse<HelloWorldV1> = HelloWorldProvider
98///     .load(DataRequest {
99///         id: DataIdentifierBorrowed::for_marker_attributes_and_locale(
100///             DataMarkerAttributes::from_str_or_panic("reverse"),
101///             &langid!("en").into(),
102///         ),
103///         ..Default::default()
104///     })
105///     .expect("Loading should succeed");
106///
107/// assert_eq!("Olleh Dlrow", reverse_hello_world.payload.get().message);
108/// ```
109///
110/// Load the nested string using an auxiliary key:
111///
112/// ```
113/// use icu_locale_core::langid;
114/// use icu_provider::hello_world::*;
115/// use icu_provider::prelude::*;
116///
117/// let nested_hello_world: DataResponse<HelloWorldV1> = HelloWorldProvider
118///     .load(DataRequest {
119///         id: DataIdentifierBorrowed::for_marker_attributes_and_locale(
120///             DataMarkerAttributes::from_str_or_panic("nested/part"),
121///             &langid!("en").into(),
122///         ),
123///         ..Default::default()
124///     })
125///     .expect("Loading should succeed");
126///
127/// assert_eq!("Hello Nested", nested_hello_world.payload.get().message);
128/// ```
129#[derive(Debug, PartialEq, Default)]
130pub struct HelloWorldProvider;
131
132impl HelloWorldProvider {
133    // Data from https://en.wiktionary.org/wiki/Hello_World#Translations
134    // Keep this sorted!
135    const DATA: &'static [(&'static str, &'static str, &'static str)] = &[
136        ("bn", "", "ওহে বিশ্ব"),
137        ("cs", "", "Ahoj světe"),
138        ("de", "", "Hallo Welt"),
139        ("de", "lowercase", "hallo welt"),
140        ("de", "uppercase", "HALLO WELT"),
141        ("de-AT", "", "Servus Welt"),
142        ("el", "", "Καλημέρα κόσμε"),
143        ("en", "", "Hello World"),
144        // WORLD
145        ("en-001", "", "Hello from 🗺️"),
146        // AFRICA
147        ("en-002", "", "Hello from 🌍"),
148        // AMERICAS
149        ("en-019", "", "Hello from 🌎"),
150        // ASIA
151        ("en-142", "", "Hello from 🌏"),
152        // GREAT BRITAIN
153        ("en-GB", "", "Hello from 🇬🇧"),
154        // ENGLAND
155        ("en-GB-u-sd-gbeng", "", "Hello from 🏴󠁧󠁢󠁥󠁮󠁧󠁿"),
156        ("en", "lowercase", "hello world"),
157        ("en", "nested/part", "Hello Nested"),
158        ("en", "reverse", "Olleh Dlrow"),
159        ("en", "rotate1", "dHello Worl"),
160        ("en", "rotate2", "ldHello Wor"),
161        ("en", "rotate3", "rldHello Wo"),
162        ("en", "uppercase", "HELLO WORLD"),
163        ("eo", "", "Saluton, Mondo"),
164        ("fa", "", "سلام دنیا‎"),
165        ("fi", "", "hei maailma"),
166        ("is", "", "Halló, heimur"),
167        ("ja", "", "こんにちは世界"),
168        ("ja", "reverse", "界世はちにんこ"),
169        ("la", "", "Ave, munde"),
170        ("pt", "", "Olá, mundo"),
171        ("ro", "", "Salut, lume"),
172        ("ru", "", "Привет, мир"),
173        ("sr", "", "Поздрав свете"),
174        ("sr-Latn", "", "Pozdrav svete"),
175        ("vi", "", "Xin chào thế giới"),
176        ("zh", "", "你好世界"),
177    ];
178
179    /// Converts this provider into a [`BufferProvider`] that uses JSON serialization.
180    #[cfg(feature = "deserialize_json")]
181    pub fn into_json_provider(self) -> HelloWorldJsonProvider {
182        HelloWorldJsonProvider
183    }
184}
185
186impl DataProvider<HelloWorldV1> for HelloWorldProvider {
187    fn load(&self, req: DataRequest) -> Result<DataResponse<HelloWorldV1>, DataError> {
188        let data = Self::DATA
189            .iter()
190            .find(|(l, a, _)| {
191                req.id.locale.strict_cmp(l.as_bytes()).is_eq()
192                    && *a == req.id.marker_attributes.as_str()
193            })
194            .map(|(_, _, v)| v)
195            .ok_or_else(|| DataErrorKind::IdentifierNotFound.with_req(HelloWorldV1::INFO, req))?;
196        Ok(DataResponse {
197            metadata: DataResponseMetadata::default().with_checksum(1234),
198            payload: DataPayload::from_static_str(data),
199        })
200    }
201}
202
203impl DryDataProvider<HelloWorldV1> for HelloWorldProvider {
204    fn dry_load(&self, req: DataRequest) -> Result<DataResponseMetadata, DataError> {
205        self.load(req).map(|r| r.metadata)
206    }
207}
208
209impl DataPayload<HelloWorldV1> {
210    /// Make a [`DataPayload`]`<`[`HelloWorldV1`]`>` from a static string slice.
211    pub fn from_static_str(s: &'static str) -> DataPayload<HelloWorldV1> {
212        DataPayload::from_owned(HelloWorld {
213            message: Cow::Borrowed(s),
214        })
215    }
216}
217
218#[cfg(feature = "deserialize_json")]
219/// A data provider returning Hello World strings in different languages as JSON blobs.
220///
221/// Mostly useful for testing.
222///
223/// # Examples
224///
225/// ```
226/// use icu_locale_core::langid;
227/// use icu_provider::hello_world::*;
228/// use icu_provider::prelude::*;
229///
230/// let german_hello_world = HelloWorldProvider
231///     .into_json_provider()
232///     .load_data(HelloWorldV1::INFO, DataRequest {
233///         id: DataIdentifierBorrowed::for_locale(&langid!("de").into()),
234///         ..Default::default()
235///     })
236///     .expect("Loading should succeed");
237///
238/// assert_eq!(german_hello_world.payload.get(), br#"{"message":"Hallo Welt"}"#);
239#[derive(Debug)]
240pub struct HelloWorldJsonProvider;
241
242#[cfg(feature = "deserialize_json")]
243impl DynamicDataProvider<BufferMarker> for HelloWorldJsonProvider {
244    fn load_data(
245        &self,
246        marker: DataMarkerInfo,
247        req: DataRequest,
248    ) -> Result<DataResponse<BufferMarker>, DataError> {
249        marker.match_marker(HelloWorldV1::INFO)?;
250        let result = HelloWorldProvider.load(req)?;
251        Ok(DataResponse {
252            metadata: DataResponseMetadata {
253                buffer_format: Some(icu_provider::buf::BufferFormat::Json),
254                ..result.metadata
255            },
256            #[expect(clippy::unwrap_used)] // HelloWorld::serialize is infallible
257            payload: DataPayload::from_owned_buffer(
258                serde_json::to_string(result.payload.get())
259                    .unwrap()
260                    .into_bytes()
261                    .into_boxed_slice(),
262            ),
263        })
264    }
265}
266
267impl IterableDataProvider<HelloWorldV1> for HelloWorldProvider {
268    fn iter_ids(&self) -> Result<BTreeSet<DataIdentifierCow<'_>>, DataError> {
269        #[expect(clippy::unwrap_used)] // hello-world
270        Ok(Self::DATA
271            .iter()
272            .map(|(l, a, _)| {
273                DataIdentifierCow::from_borrowed_and_owned(
274                    DataMarkerAttributes::from_str_or_panic(a),
275                    l.parse().unwrap(),
276                )
277            })
278            .collect())
279    }
280}
281
282#[cfg(feature = "export")]
283icu_provider::export::make_exportable_provider!(HelloWorldProvider, [HelloWorldV1,]);
284
285define_preferences!(
286    /// Hello World Preferences.
287    [Copy]
288    HelloWorldFormatterPreferences, {}
289);
290
291/// A type that formats localized "hello world" strings.
292///
293/// This type is intended to take the shape of a typical ICU4X formatter API.
294///
295/// # Examples
296///
297/// ```
298/// use icu_locale_core::locale;
299/// use icu_provider::hello_world::{HelloWorldFormatter, HelloWorldProvider};
300/// use writeable::assert_writeable_eq;
301///
302/// let fmt = HelloWorldFormatter::try_new_unstable(
303///     &HelloWorldProvider,
304///     locale!("eo").into(),
305/// )
306/// .expect("locale exists");
307///
308/// assert_writeable_eq!(fmt.format(), "Saluton, Mondo");
309/// ```
310#[derive(Debug)]
311pub struct HelloWorldFormatter {
312    data: DataPayload<HelloWorldV1>,
313}
314
315/// A formatted hello world message. Implements [`Writeable`].
316///
317/// For an example, see [`HelloWorldFormatter`].
318#[derive(Debug)]
319pub struct FormattedHelloWorld<'l> {
320    data: &'l HelloWorld<'l>,
321}
322
323impl HelloWorldFormatter {
324    /// Creates a new [`HelloWorldFormatter`] for the specified locale.
325    ///
326    /// [📚 Help choosing a constructor](icu_provider::constructors)
327    pub fn try_new(prefs: HelloWorldFormatterPreferences) -> Result<Self, DataError> {
328        Self::try_new_unstable(&HelloWorldProvider, prefs)
329    }
330
331    icu_provider::gen_buffer_data_constructors!((prefs: HelloWorldFormatterPreferences) -> error: DataError,
332        functions: [
333            try_new: skip,
334            try_new_with_buffer_provider,
335            try_new_unstable,
336            Self,
337    ]);
338
339    #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
340    pub fn try_new_unstable<P>(
341        provider: &P,
342        prefs: HelloWorldFormatterPreferences,
343    ) -> Result<Self, DataError>
344    where
345        P: DataProvider<HelloWorldV1>,
346    {
347        let locale = HelloWorldV1::make_locale(prefs.locale_preferences);
348        let data = provider
349            .load(DataRequest {
350                id: DataIdentifierBorrowed::for_locale(&locale),
351                ..Default::default()
352            })?
353            .payload;
354        Ok(Self { data })
355    }
356
357    /// Formats a hello world message, returning a [`FormattedHelloWorld`].
358    pub fn format<'l>(&'l self) -> FormattedHelloWorld<'l> {
359        FormattedHelloWorld {
360            data: self.data.get(),
361        }
362    }
363
364    /// Formats a hello world message, returning a [`String`].
365    pub fn format_to_string(&self) -> String {
366        self.format().write_to_string().into_owned()
367    }
368}
369
370impl Writeable for FormattedHelloWorld<'_> {
371    fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
372        self.data.message.write_to(sink)
373    }
374
375    fn writeable_borrow(&self) -> Option<&str> {
376        self.data.message.writeable_borrow()
377    }
378
379    fn writeable_length_hint(&self) -> writeable::LengthHint {
380        self.data.message.writeable_length_hint()
381    }
382}
383
384writeable::impl_display_with_writeable!(FormattedHelloWorld<'_>);
385
386#[cfg(feature = "export")]
387#[test]
388fn test_iter() {
389    use crate::IterableDataProvider;
390    use icu_locale_core::locale;
391
392    let ids = HelloWorldProvider.iter_ids().unwrap();
393
394    assert_eq!(ids.len(), HelloWorldProvider::DATA.len());
395
396    assert!(ids.contains(&DataIdentifierCow::from_borrowed_and_owned(
397        DataMarkerAttributes::from_str_or_panic("reverse"),
398        locale!("en").into()
399    )));
400}