Crates.io | typed-i18n |
lib.rs | typed-i18n |
version | 0.6.1 |
source | src |
created_at | 2024-06-18 18:08:43.970411 |
updated_at | 2024-06-28 20:13:30.478894 |
description | A type safe i18n system |
homepage | |
repository | https://github.com/alexkazik/typed-i18n |
max_upload_size | |
id | 1275711 |
size | 45,498 |
Convert a language file and an enum into a type safe i18n system.
Yaml language file: (json and lrc is also supported, more below)
hello_world:
en: Hello World
de: Hallo Welt
hello_you:
en: Hello %{name}
Code:
#[derive(Copy, Clone, TypedI18N)]
#[typed_i18n(filename = "example.yaml")]
#[typed_i18n(builder = "mixed_str", prefix = "str_")]
enum Language { En, De }
Generated code:
impl Language {
fn str_hello_world(self) -> &'static str;
fn str_hello_you(self, name: &str) -> String;
}
Usage:
fn print_hello(language: Language, name: Option<&str>){
if let Some(name) = name {
println!("{}", language.str_hello_you(name));
} else {
println!("{}", language.str_hello_world());
}
}
A global stored language is also supported, see global below.
Different generators add different code:
#[typed_i18n(builder = "static_str", prefix = "sta_")]
#[typed_i18n(builder = "String")]
Generated code:
impl Language {
fn sta_hello_world(self) -> &'static str;
// The static_str builder skips all parameterized messages
fn hello_world(self) -> String;
fn hello_you(self, name: &str) -> String;
}
Also types other than strings are possible:
#in addition to the messages above
hello_with_icon:
en: Hello %{name}*{icon}
#[typed_i18n(builder = "HtmlBuilder", input = "Html", prefix = "html_")]
Generated code:
impl Language {
fn html_hello_world(self) -> <HtmlBuilder as Builder>::Output;
fn html_hello_you(self, name: &str) -> <HtmlBuilder as Builder>::Output;
fn html_hello_with_icon<T1: Into<Html>>(
self,
name: &str,
icon: T1,
) -> <HtmlBuilder as Builder>::Output;
}
See examples for a HtmlBuilder
for yew::Html
implementation.
Fields:
filename
: the path to the translations, relative to the crate root (required).separator
: used for combining paths of a tree, default: _
.global
: used for a global stored language, see global below, default: not used.Example:
#[typed_i18n(filename = "example.yaml", separator = "_")]
The messages can be supplied in
json:
{"hello_world": {"en": "Hello World"}}
The yaml and json files may have a _version: 2
entry, to be compatible
with other i18n tools. (Other numbers are an error, omitting it is ok.)
The yaml and json files may have a deeper tree. In that case the separator is used to join the segments into a function name.
Example:
hello:
world:
en: Hello World
you:
en: Hello %{name}
With the separator _
it will result in the same names as the examples above.
This may help you structure the messages.
Since the name is a function name a .
as a separator is not allowed, but you can use ยท
(U+00B7).
lrc:
; lines starting with `;` or `/` will be skipped
#hello_world
en Hello World
Fields:
builder
: The name of an item which implements [Builder
], or a special value.prefix
: Prefix for all functions generated by this builder, default: the empty string.str_conversion
: How to convert str parameters, default ref
.input
: Type of the input (for typed inputs), default: no input.input_conversion
: How to convert the parameter into the input type, default: into
.builder
Must be either a special value or a type for which [Builder
] is implemented.
All builders without a input type will skip all messages for it.
All the builders below are built-in. The input
must not be set for these. Always available:
static_str
: all messages without parameters have the return type &'static str
. All others are skipped.mixed_str
: all messages without parameters have the return type &'static str
all others will have the return type String
.String
Cow<'static, str>
_
: The functions will be generic over the builder type. This is sometimes not helpful,
e.g. when .into()
or .as_ref()
will be called on the result of the function.All except static_str
and _
require the feature alloc
(enabled by default) and that String
or Cow
is in scope.
To learn about custom type builder see the example above and in the examples directory.
prefix
All functions of this builder
will be composed of the prefix and the message name.
Using identical prefixes or overlapping names will result in functions with identical names and thus result in a compile error. This will not be checked by the derive macro.
str_conversion
The conversion for all string (normal) %{param}
parameters:
ref
(default): fn str_hello_you(self, name: &str) -> String
.as_ref
: fn str_hello_you<S1: AsRef<str>>(self, name: S1) -> String
.input
Type of the input for typed *{param}
parameters.
All builders without input
will silently skip all messages with typed parameters.
With _
a generic function over the input type is created. May lead to the same problems as
a generic builder type.
input_conversion
How to convert the types inputs:
value
: The input type as parameter:
fn html_hello_with_icon(self, name: &str, icon: Input) -> <HtmlBuilder as BuilderFromValue>::Output
into
(default): Something that can be converted into the input type:
fn html_hello_with_icon<T1: Into<Input>>(self, name: &str, icon: T1) -> <HtmlBuilder as BuilderFromValue>::Output
ref
: A reference to the input type:
fn html_hello_with_icon(self, name: &str, icon: &Input) -> <HtmlBuilder as BuilderFromRef>::Output
as_ref
: Something that can be converted into a reference to the input type:
fn html_hello_with_icon<T1: AsRef<Input>>(self, name: &str, icon: T1) -> <HtmlBuilder as BuilderFromRef>::Output
For value
and into
to work the builder must also implement [BuilderFromValue
].
For ref
and as_ref
to work the builder must also implement [BuilderFromRef
].
The enum values can be annotated with:
name
: The name of the language in the messages file, defaults to the name of the value in snake_case
.fallback
: A space and/or comma separated list of language names which defines which language
should be used when a message is missing. Default: all languages in listing order (not necessary in numerical order).default
: Is used for a global storage. Only one language may be the default.Example:
#[derive(Copy, Clone, TypedI18N)]
#[typed_i18n(filename = "example.yaml")]
#[typed_i18n(builder = "mixed_str", prefix = "str_")]
enum Language {
De,
#[typed_i18n(name = "en")]
English,
#[typed_i18n(fallback = "en, de")]
EnAu,
}
It is possible to generate a global language storage.
Code:
#[derive(Copy, Clone, TypedI18N)]
#[typed_i18n(filename = "example.yaml", global = "atomic")]
#[typed_i18n(builder = "static_str")]
enum Language { En, #[typed_i18n(default = "true")] De }
Generated code:
impl Language {
fn global() -> Self;
fn set_global(self);
}
Example usage:
// de is the default
assert_eq!(Language::global().hello_world(), "Hallo Welt");
Language::En.set_global();
assert_eq!(Language::global().hello_world(), "Hello world");
The default language (either marked as such, see example above, or the first one) is initially stored as the global language.
Currently atomic
is the only implementation, which uses an AtomicU8
to store the language. The conversion does not depend on the representation of the enum.
In case of more than 256 languages an AtomicUsize
is used.
alloc
, enabled by default: Provide Builder implementations for String
and Cow<'static, str>
, also support mixed_str
.The library is always no_std
.