Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // An interesting pattern on how to localize error messages
- // without repeating yourself:
- // Say you have this error enum and you want to translate the error
- // into multiple languages...
- enum AppError {
- HelloError,
- }
- enum Language {
- German,
- English,
- Spanish,
- }
- // First, define as many identical modules with identical
- // defined constants as you have languages.
- //
- // Seperating language-specific error messages into modules
- // makes it easy to work with translators, because you
- // have all your language-specific strings in one place
- //
- // The names of the const items have to be identical, which is
- // the whole point of this trick.
- mod en_us {
- pub const HELLO: &str = "Hello!";
- }
- mod de_de {
- pub const HELLO: &str = "Hallo!";
- }
- mod es_es {
- pub const HELLO: &str = "¡Hola";
- }
- // This macro generates a function, given a function name and
- // a target module name. It only works on the AppError, but that is
- // fine since usually you only have one big error enum in your
- // app.
- //
- // Should any constant not be defined in a module or if there is a
- // mismatch between modules, the macro expansion will fail with
- // "couldn't find constant HELLO in module es_es" for example
- // ... which tells you pretty clearly that the HELLO message
- // isn't yet translated to Spanish
- macro_rules! localize_app_error {
- ($fn_name:ident, $language_module:ident) => (
- fn $fn_name(&self) -> &'static str {
- // This is the trick, basically: We pattern-match on the
- // AppError only once (in the macro), but when we
- // instantiate the macro we generate multiple functions,
- // without repeating the match statement.
- //
- // Since matches are exhaustive we can't "forget"
- // to not translate one error.
- use AppError::*;
- match self {
- HelloError => $language_module::HELLO,
- // other error cases go here
- }
- }
- )
- }
- impl AppError {
- // Generate the translation functions
- //
- // You could also define them as free-standing functions.
- // The functions are private to the AppError struct, so they
- // can only be called via the public interface
- // (the `.translate()` function)
- localize_app_error!(translate_german, de_de);
- localize_app_error!(translate_english, en_us);
- localize_app_error!(translate_spanish, es_es);
- pub fn translate(&self, language: Language) -> &'static str {
- use Language::*;
- match language {
- German => self.translate_german(),
- English => self.translate_english(),
- Spanish => self.translate_spanish(),
- }
- }
- }
- fn main() {
- // So here you can specify the language at runtime,
- // (ex. if your app allows you to set the language)
- //
- // The benefit is that you won't have any un-translated
- // error messages because if you would, it wouldn't compile.
- let error = AppError::HelloError;
- println!("{}", error.translate(Language::English));
- println!("{}", error.translate(Language::German));
- println!("{}", error.translate(Language::Spanish));
- }
Add Comment
Please, Sign In to add comment