Add examples for `l10n_embed_interaction`

finchie
Aug 8, 2025, 10:46 AM
YUW3BUXXSWXHLNQNVDOCHSZ44G4NJ64T75DFOO6KKIFFTYXBBF7QC

Dependencies

  • [2] JUV7C6ET Create initial prototype of `fluent_embed_interaction`

Change contents

  • file addition: examples (d--r------)
    [2.36]
  • file addition: prompt (d--r------)
    [0.20]
  • file addition: main.rs (----------)
    [0.40]
    //! Example showing various localized interactions
    use icu_locale::locale;
    use l10n_embed_derive::localize;
    use l10n_embed_interaction::{Confirm, Editor, Input, Password, Select};
    use l10n_embed_interaction::{InteractionEnvironment, InteractionError};
    #[localize("examples/prompt/locale/**/prompt_selection.ftl")]
    enum PromptSelection {
    Confirm,
    Editor,
    Input,
    Password,
    }
    #[localize("examples/prompt/locale/**/prompts.ftl")]
    enum Prompt {
    Confirm,
    Input,
    Password,
    PasswordConfirmation,
    Select,
    }
    #[localize("examples/prompt/locale/**/errors.ftl")]
    enum PromptError {
    NonAlphabeticInput,
    NonPalindromeInput,
    PasswordTooShort {
    provided_length: usize,
    expected_length: usize,
    },
    PasswordMismatch,
    }
    const ALWAYS_INTERACTIVE: &str = "Attempted to interact in a non-interactive environment";
    const DEFAULT_SELECTION: usize = 2;
    const MINIMUM_PASSWORD_LENGTH: usize = 2;
    const PROMPT_SELECTIONS: [PromptSelection; 4] = [
    PromptSelection::Confirm,
    PromptSelection::Editor,
    PromptSelection::Input,
    PromptSelection::Password,
    ];
    fn main() -> Result<(), InteractionError> {
    let environment = InteractionEnvironment::new(locale!("en-US"), true);
    let selected_index = Select::new(&environment, Prompt::Select)
    .with_items(&PROMPT_SELECTIONS)
    .with_default(DEFAULT_SELECTION)
    .interact()?
    .expect(ALWAYS_INTERACTIVE);
    match PROMPT_SELECTIONS[selected_index] {
    PromptSelection::Confirm => {
    let confirmation = Confirm::new(&environment, Prompt::Confirm)
    .with_default(true)
    .interact()?
    .expect(ALWAYS_INTERACTIVE);
    let message = match confirmation {
    true => "hooray!",
    false => "dang..",
    };
    println!("{message}");
    }
    PromptSelection::Editor => {
    let edited = Editor::new(&environment, "toml").edit("Some text for you to edit!")?;
    match edited {
    Some(saved_text) => println!(
    "The file was saved successfully (total lines: {})",
    saved_text.lines().count()
    ),
    None => println!("No text was saved.."),
    }
    }
    PromptSelection::Input => {
    let input = Input::new(&environment, Prompt::Input)
    // `Input::with_default` accepts anything that implements `Localize`,
    // so this default could also be localized
    .with_default("racecar")
    .with_validator(|input| {
    if !input
    .chars()
    .all(|character| character.is_alphabetic() && !character.is_whitespace())
    {
    Err(PromptError::NonAlphabeticInput)
    } else if input != &input.chars().rev().collect::<String>() {
    Err(PromptError::NonPalindromeInput)
    } else {
    Ok(())
    }
    })
    .interact()?
    .expect(ALWAYS_INTERACTIVE);
    println!("Your palindrome is: {input}!")
    }
    PromptSelection::Password => {
    let password = Password::new(&environment, Prompt::Password)
    .with_validator(|password| {
    if password.len() >= MINIMUM_PASSWORD_LENGTH {
    Ok(())
    } else {
    Err(PromptError::PasswordTooShort {
    provided_length: password.len(),
    expected_length: MINIMUM_PASSWORD_LENGTH,
    })
    }
    })
    .with_confirmation(Prompt::PasswordConfirmation, PromptError::PasswordMismatch)
    .interact()?
    .expect(ALWAYS_INTERACTIVE);
    println!("Your password is: {password}");
    }
    }
    Ok(())
    }
  • file addition: locale (d--r------)
    [0.40]
  • file addition: en-US (d--r------)
    [0.4164]
  • file addition: prompts.ftl (----------)
    [0.4183]
    confirm = Pretty cool, right??
    input = Enter a palindrome
    password = Very secret password
    password-confirmation = Confirm your password
    select = Which example would you like to try?
  • file addition: prompt_selection.ftl (----------)
    [0.4183]
    confirm = Show a confirmation prompt
    editor = Open an editor window
    input = Get the user's input
    password = Ask for a password (with confirmation)
  • file addition: errors.ftl (----------)
    [0.4183]
    non-alphabetic-input = Input contains non-alphabetic characters!
    non-palindrome-input = That's not a palindrome..
    password-too-short = Password too short! Provided { $provided-length } character, expected at least { $expected-length }.
    password-mismatch = Passwords do not match!
  • file addition: progress (d--r------)
    [0.20]
  • file addition: main.rs (----------)
    [0.4933]
    //! Example showing localized progress bars
    use icu_locale::locale;
    use l10n_embed_derive::localize;
    use l10n_embed_interaction::{InteractionEnvironment, InteractionError, ProgressBar};
    #[localize("examples/progress/*.ftl")]
    enum ProgressMessage {
    LongProgress,
    ShortProgress,
    Hello,
    }
    fn main() -> Result<(), InteractionError> {
    let environment = InteractionEnvironment::new(locale!("en-US"), true);
    let long_progress = ProgressBar::new(&environment, ProgressMessage::LongProgress, 200);
    let short_progress = ProgressBar::new(&environment, ProgressMessage::ShortProgress, 100);
    for _ in 0..100 {
    long_progress.increment(1);
    short_progress.increment(1);
    std::thread::sleep(std::time::Duration::from_millis(10));
    }
    short_progress.finish();
    environment.emit_message(ProgressMessage::Hello)?;
    for _ in 0..100 {
    long_progress.increment(1);
    std::thread::sleep(std::time::Duration::from_millis(10));
    }
    Ok(())
    }
  • file addition: en-US.ftl (----------)
    [0.4933]
    long-progress = Running the example
    short-progress = Finishing a quick task
    hello = Finished the first task!