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::string::String;
14use core::fmt::Debug;
15use writeable::Writeable;
16use yoke::*;
17use zerofrom::*;
18
19/// A struct containing "Hello World" in the requested language.
20#[derive(Debug, PartialEq, Clone, Yokeable, ZeroFrom)]
21#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
22#[cfg_attr(
23 any(feature = "deserialize_json", feature = "datagen"),
24 derive(serde::Serialize)
25)]
26#[cfg_attr(feature = "datagen", derive(databake::Bake))]
27#[cfg_attr(feature = "datagen", databake(path = icu_provider::hello_world))]
28pub struct HelloWorldV1<'data> {
29 /// The translation of "Hello World".
30 #[cfg_attr(feature = "serde", serde(borrow))]
31 pub message: Cow<'data, str>,
32}
33
34impl Default for HelloWorldV1<'_> {
35 fn default() -> Self {
36 HelloWorldV1 {
37 message: Cow::Borrowed("(und) Hello World"),
38 }
39 }
40}
41
42/// Marker type for [`HelloWorldV1`].
43#[cfg_attr(feature = "datagen", derive(Default, databake::Bake))]
44#[cfg_attr(feature = "datagen", databake(path = icu_provider::hello_world))]
45#[derive(Debug)]
46pub struct HelloWorldV1Marker;
47
48impl DataMarker for HelloWorldV1Marker {
49 type Yokeable = HelloWorldV1<'static>;
50}
51
52impl KeyedDataMarker for HelloWorldV1Marker {
53 const KEY: DataKey = icu_provider::data_key!("core/helloworld@1");
54}
55
56/// A data provider returning Hello World strings in different languages.
57///
58/// Mostly useful for testing.
59///
60/// # Examples
61///
62/// ```
63/// use icu_locid::locale;
64/// use icu_provider::hello_world::*;
65/// use icu_provider::prelude::*;
66///
67/// let german_hello_world: DataPayload<HelloWorldV1Marker> =
68/// HelloWorldProvider
69/// .load(DataRequest {
70/// locale: &locale!("de").into(),
71/// metadata: Default::default(),
72/// })
73/// .expect("Loading should succeed")
74/// .take_payload()
75/// .expect("Data should be present");
76///
77/// assert_eq!("Hallo Welt", german_hello_world.get().message);
78/// ```
79///
80/// Load the reverse string using an auxiliary key:
81///
82/// ```
83/// use icu_provider::hello_world::*;
84/// use icu_provider::prelude::*;
85///
86/// let reverse_hello_world: DataPayload<HelloWorldV1Marker> =
87/// HelloWorldProvider
88/// .load(DataRequest {
89/// locale: &"en+reverse".parse().unwrap(),
90/// metadata: Default::default(),
91/// })
92/// .expect("Loading should succeed")
93/// .take_payload()
94/// .expect("Data should be present");
95///
96/// assert_eq!("Olleh Dlrow", reverse_hello_world.get().message);
97/// ```
98#[derive(Debug, PartialEq, Default)]
99pub struct HelloWorldProvider;
100
101impl HelloWorldProvider {
102 // Data from https://en.wiktionary.org/wiki/Hello_World#Translations
103 // Keep this sorted!
104 const DATA: &'static [(&'static str, &'static str)] = &[
105 ("bn", "ওহে বিশ্ব"),
106 ("cs", "Ahoj světe"),
107 ("de", "Hallo Welt"),
108 ("de-AT", "Servus Welt"),
109 ("el", "Καλημέρα κόσμε"),
110 ("en", "Hello World"),
111 ("en+reverse", "Olleh Dlrow"),
112 ("en-001", "Hello from 🗺️"), // WORLD
113 ("en-002", "Hello from 🌍"), // AFRICA
114 ("en-019", "Hello from 🌎"), // AMERICAS
115 ("en-142", "Hello from 🌏"), // ASIA
116 ("en-GB", "Hello from 🇬🇧"), // GREAT BRITAIN
117 ("en-GB-u-sd-gbeng", "Hello from 🏴󠁧󠁢󠁥󠁮󠁧󠁿"), // ENGLAND
118 ("eo", "Saluton, Mondo"),
119 ("fa", "سلام دنیا‎"),
120 ("fi", "hei maailma"),
121 ("is", "Halló, heimur"),
122 ("ja", "こんにちは世界"),
123 ("ja+reverse", "界世はちにんこ"),
124 ("la", "Ave, munde"),
125 ("pt", "Olá, mundo"),
126 ("ro", "Salut, lume"),
127 ("ru", "Привет, мир"),
128 ("sr", "Поздрав свете"),
129 ("sr-Latn", "Pozdrav svete"),
130 ("vi", "Xin chào thế giới"),
131 ("zh", "你好世界"),
132 ];
133
134 /// Converts this provider into a [`BufferProvider`] that uses JSON serialization.
135 #[cfg(feature = "deserialize_json")]
136 pub fn into_json_provider(self) -> HelloWorldJsonProvider {
137 HelloWorldJsonProvider
138 }
139}
140
141impl DataProvider<HelloWorldV1Marker> for HelloWorldProvider {
142 fn load(&self, req: DataRequest) -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
143 #[allow(clippy::indexing_slicing)] // binary_search
144 let data: &str = Self::DATA
145 .binary_search_by(|(k, _)| req.locale.strict_cmp(k.as_bytes()).reverse())
146 .map(|i| Self::DATA[i].1)
147 .map_err(|_| DataErrorKind::MissingLocale.with_req(HelloWorldV1Marker::KEY, req))?;
148 Ok(DataResponse {
149 metadata: Default::default(),
150 payload: Some(DataPayload::from_static_str(data)),
151 })
152 }
153}
154
155impl DataPayload<HelloWorldV1Marker> {
156 /// Make a [`DataPayload`]`<`[`HelloWorldV1Marker`]`>` from a static string slice.
157 pub fn from_static_str(s: &'static str) -> DataPayload<HelloWorldV1Marker> {
158 DataPayload::from_owned(data:HelloWorldV1 {
159 message: Cow::Borrowed(s),
160 })
161 }
162}
163
164// AnyProvider support.
165#[cfg(not(feature = "datagen"))]
166icu_provider::impl_dynamic_data_provider!(HelloWorldProvider, [HelloWorldV1Marker,], AnyMarker);
167
168#[cfg(feature = "deserialize_json")]
169/// A data provider returning Hello World strings in different languages as JSON blobs.
170///
171/// Mostly useful for testing.
172///
173/// # Examples
174///
175/// ```
176/// use icu_locid::locale;
177/// use icu_provider::hello_world::*;
178/// use icu_provider::prelude::*;
179///
180/// let german_hello_world = HelloWorldProvider
181/// .into_json_provider()
182/// .load_buffer(HelloWorldV1Marker::KEY, DataRequest {
183/// locale: &locale!("de").into(),
184/// metadata: Default::default(),
185/// })
186/// .expect("Loading should succeed")
187/// .take_payload()
188/// .expect("Data should be present");
189///
190/// assert_eq!(german_hello_world.get(), br#"{"message":"Hallo Welt"}"#);
191#[derive(Debug)]
192pub struct HelloWorldJsonProvider;
193
194#[cfg(feature = "deserialize_json")]
195impl BufferProvider for HelloWorldJsonProvider {
196 fn load_buffer(
197 &self,
198 key: DataKey,
199 req: DataRequest,
200 ) -> Result<DataResponse<BufferMarker>, DataError> {
201 key.match_key(HelloWorldV1Marker::KEY)?;
202 let result = HelloWorldProvider.load(req)?;
203 let (mut metadata, old_payload) =
204 DataResponse::<HelloWorldV1Marker>::take_metadata_and_payload(result)?;
205 metadata.buffer_format = Some(icu_provider::buf::BufferFormat::Json);
206 #[allow(clippy::unwrap_used)] // HelloWorldV1::serialize is infallible
207 Ok(DataResponse {
208 metadata,
209 payload: Some(DataPayload::from_owned_buffer(
210 serde_json::to_string(old_payload.get())
211 .unwrap()
212 .into_bytes()
213 .into_boxed_slice(),
214 )),
215 })
216 }
217}
218
219#[cfg(feature = "datagen")]
220impl icu_provider::datagen::IterableDataProvider<HelloWorldV1Marker> for HelloWorldProvider {
221 fn supported_locales(&self) -> Result<Vec<DataLocale>, DataError> {
222 #[allow(clippy::unwrap_used)] // datagen
223 Ok(Self::DATA.iter().map(|(s, _)| s.parse().unwrap()).collect())
224 }
225}
226
227#[cfg(feature = "datagen")]
228icu_provider::make_exportable_provider!(HelloWorldProvider, [HelloWorldV1Marker,]);
229
230/// A type that formats localized "hello world" strings.
231///
232/// This type is intended to take the shape of a typical ICU4X formatter API.
233///
234/// # Examples
235///
236/// ```
237/// use icu_locid::locale;
238/// use icu_provider::hello_world::{HelloWorldFormatter, HelloWorldProvider};
239/// use writeable::assert_writeable_eq;
240///
241/// let fmt = HelloWorldFormatter::try_new_unstable(
242/// &HelloWorldProvider,
243/// &locale!("eo").into(),
244/// )
245/// .expect("locale exists");
246///
247/// assert_writeable_eq!(fmt.format(), "Saluton, Mondo");
248/// ```
249#[derive(Debug)]
250pub struct HelloWorldFormatter {
251 data: DataPayload<HelloWorldV1Marker>,
252}
253
254/// A formatted hello world message. Implements [`Writeable`].
255///
256/// For an example, see [`HelloWorldFormatter`].
257#[derive(Debug)]
258pub struct FormattedHelloWorld<'l> {
259 data: &'l HelloWorldV1<'l>,
260}
261
262impl HelloWorldFormatter {
263 /// Creates a new [`HelloWorldFormatter`] for the specified locale.
264 ///
265 /// [📚 Help choosing a constructor](icu_provider::constructors)
266 pub fn try_new(locale: &DataLocale) -> Result<Self, DataError> {
267 Self::try_new_unstable(&HelloWorldProvider, locale)
268 }
269
270 icu_provider::gen_any_buffer_data_constructors!(locale: include, options: skip, error: DataError,
271 #[cfg(skip)]
272 functions: [
273 try_new,
274 try_new_with_any_provider,
275 try_new_with_buffer_provider,
276 try_new_unstable,
277 Self,
278 ]);
279
280 #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
281 pub fn try_new_unstable<P>(provider: &P, locale: &DataLocale) -> Result<Self, DataError>
282 where
283 P: DataProvider<HelloWorldV1Marker>,
284 {
285 let data = provider
286 .load(DataRequest {
287 locale,
288 metadata: Default::default(),
289 })?
290 .take_payload()?;
291 Ok(Self { data })
292 }
293
294 /// Formats a hello world message, returning a [`FormattedHelloWorld`].
295 #[allow(clippy::needless_lifetimes)] // documentary example
296 pub fn format<'l>(&'l self) -> FormattedHelloWorld<'l> {
297 FormattedHelloWorld {
298 data: self.data.get(),
299 }
300 }
301
302 /// Formats a hello world message, returning a [`String`].
303 pub fn format_to_string(&self) -> String {
304 self.format().write_to_string().into_owned()
305 }
306}
307
308impl<'l> Writeable for FormattedHelloWorld<'l> {
309 fn write_to<W: core::fmt::Write + ?Sized>(&self, sink: &mut W) -> core::fmt::Result {
310 self.data.message.write_to(sink)
311 }
312
313 fn write_to_string(&self) -> Cow<str> {
314 self.data.message.clone()
315 }
316
317 fn writeable_length_hint(&self) -> writeable::LengthHint {
318 self.data.message.writeable_length_hint()
319 }
320}
321
322writeable::impl_display_with_writeable!(FormattedHelloWorld<'_>);
323
324#[cfg(feature = "datagen")]
325#[test]
326fn test_iter() {
327 use crate::datagen::IterableDataProvider;
328 use icu_locid::locale;
329
330 assert_eq!(
331 HelloWorldProvider.supported_locales().unwrap(),
332 vec![
333 locale!("bn").into(),
334 locale!("cs").into(),
335 locale!("de").into(),
336 locale!("de-AT").into(),
337 locale!("el").into(),
338 locale!("en").into(),
339 "en+reverse".parse().unwrap(),
340 locale!("en-001").into(),
341 locale!("en-002").into(),
342 locale!("en-019").into(),
343 locale!("en-142").into(),
344 locale!("en-GB").into(),
345 locale!("en-GB-u-sd-gbeng").into(),
346 locale!("eo").into(),
347 locale!("fa").into(),
348 locale!("fi").into(),
349 locale!("is").into(),
350 locale!("ja").into(),
351 "ja+reverse".parse().unwrap(),
352 locale!("la").into(),
353 locale!("pt").into(),
354 locale!("ro").into(),
355 locale!("ru").into(),
356 locale!("sr").into(),
357 locale!("sr-Latn").into(),
358 locale!("vi").into(),
359 locale!("zh").into()
360 ]
361 );
362}
363