Guest User

Untitled

a guest
May 24th, 2018
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.12 KB | None | 0 0
  1. // An interesting pattern on how to localize error messages
  2. // without repeating yourself:
  3.  
  4. // Say you have this error enum and you want to translate the error
  5. // into multiple languages...
  6. enum AppError {
  7. HelloError,
  8. }
  9.  
  10. enum Language {
  11. German,
  12. English,
  13. Spanish,
  14. }
  15.  
  16. // First, define as many identical modules with identical
  17. // defined constants as you have languages.
  18. //
  19. // Seperating language-specific error messages into modules
  20. // makes it easy to work with translators, because you
  21. // have all your language-specific strings in one place
  22. //
  23. // The names of the const items have to be identical, which is
  24. // the whole point of this trick.
  25. mod en_us {
  26. pub const HELLO: &str = "Hello!";
  27. }
  28. mod de_de {
  29. pub const HELLO: &str = "Hallo!";
  30. }
  31. mod es_es {
  32. pub const HELLO: &str = "¡Hola";
  33. }
  34.  
  35. // This macro generates a function, given a function name and
  36. // a target module name. It only works on the AppError, but that is
  37. // fine since usually you only have one big error enum in your
  38. // app.
  39. //
  40. // Should any constant not be defined in a module or if there is a
  41. // mismatch between modules, the macro expansion will fail with
  42. // "couldn't find constant HELLO in module es_es" for example
  43. // ... which tells you pretty clearly that the HELLO message
  44. // isn't yet translated to Spanish
  45. macro_rules! localize_app_error {
  46. ($fn_name:ident, $language_module:ident) => (
  47. fn $fn_name(&self) -> &'static str {
  48. // This is the trick, basically: We pattern-match on the
  49. // AppError only once (in the macro), but when we
  50. // instantiate the macro we generate multiple functions,
  51. // without repeating the match statement.
  52. //
  53. // Since matches are exhaustive we can't "forget"
  54. // to not translate one error.
  55. use AppError::*;
  56. match self {
  57. HelloError => $language_module::HELLO,
  58. // other error cases go here
  59. }
  60. }
  61. )
  62. }
  63.  
  64. impl AppError {
  65. // Generate the translation functions
  66. //
  67. // You could also define them as free-standing functions.
  68. // The functions are private to the AppError struct, so they
  69. // can only be called via the public interface
  70. // (the `.translate()` function)
  71. localize_app_error!(translate_german, de_de);
  72. localize_app_error!(translate_english, en_us);
  73. localize_app_error!(translate_spanish, es_es);
  74.  
  75. pub fn translate(&self, language: Language) -> &'static str {
  76. use Language::*;
  77. match language {
  78. German => self.translate_german(),
  79. English => self.translate_english(),
  80. Spanish => self.translate_spanish(),
  81. }
  82. }
  83. }
  84.  
  85. fn main() {
  86. // So here you can specify the language at runtime,
  87. // (ex. if your app allows you to set the language)
  88. //
  89. // The benefit is that you won't have any un-translated
  90. // error messages because if you would, it wouldn't compile.
  91. let error = AppError::HelloError;
  92.  
  93. println!("{}", error.translate(Language::English));
  94. println!("{}", error.translate(Language::German));
  95. println!("{}", error.translate(Language::Spanish));
  96. }
Add Comment
Please, Sign In to add comment