Typed BCP47 language tags with names, plural metadata, and conversion helpers to common libraries.
Language tags are defined in BCP47. A friendly overview is available in the W3C article “Language tags in HTML and XML.” These tags are commonly used in HTML and in the Content-Language and Accept-Language HTTP headers.
- Typed coverage of BCP47 language tags through a single
Languageenum. - Conversion helpers:
tag,name, andlocal_namegive tags, English names, and native names, withTryFromfor parsing. Language::all()provides a compile-time array for iterating over every language without allocation.- Optional
serdefeature for serializing and deserializing language values. - Code is generated directly from the translation.io “languages with plural cases” page;
cargo buildenforces validity and thelanguagebinary downloads fresh data when regenerating. - Optional ICU4X interop (
icu_locale_corefeature) for converting to/fromLocaleandLanguageIdentifier. - Optional whatlang interop (
whatlangfeature) for converting to/fromwhatlang::Langwith clear error reporting. - Optional lingua interop (
linguafeature) for converting to/fromlingua::Languagewith clear error reporting. - Optional SQLx interop (
sqlx-postgres/sqlx-mysql/sqlx-sqlite) forType/Encode/Decodesupport using textual tags.
// crates.iouse language::Language;let en = Language::En;assert_eq!(en.tag(),"en");assert_eq!(Language::try_from("en").unwrap(),Language::En);assert_eq!(en.name(),"English");assert_eq!(en.local_name(),"English");Parse user input safely (any invalid tag becomes a typed error):
// crates.iouse language::Language;let parsed:Result<Language,_> = Language::try_from("zh-Hant");assert!(parsed.is_ok());let bad = Language::try_from("zz-INVALID");assert!(bad.is_err());Iterate over every language without allocation:
// crates.iouse language::Language;let tags:Vec<&'staticstr> = Language::all().iter().map(Language::tag).collect();assert!(tags.contains(&"fr-CA"));serde (enable the serde feature):
// crates.iouse language::Language;use serde::{Deserialize,Serialize};#[derive(Debug,Serialize,Deserialize,PartialEq)]structPayload{lang:Language,}let json = r#"{"lang":"es-MX"}"#;let payload:Payload = serde_json::from_str(json)?;assert_eq!(payload.lang,Language::EsMx);ICU4X interop (enable icu_locale_core):
// crates.iouse icu_locale_core::Locale;use language::Language;let locale:Locale = "pt-BR".parse()?;let language = Language::try_from(&locale)?;assert_eq!(language.tag(),"pt-BR");whatlang interop (enable whatlang):
// crates.iouse language::Language;use whatlang::Lang;let lang = Language::try_from(Lang::Ukr)?;assert_eq!(lang,Language::Uk);lingua interop (enable lingua):
// crates.iouse language::Language;use lingua::LanguageasLinguaLanguage;let lang = Language::try_from(LinguaLanguage::Japanese)?;assert_eq!(lang,Language::Ja);SQLx (enable one of the sqlx-* features):
// crates.iouse language::Language;use sqlx::types::Json;// Language stores as a text tag; works with Postgres/MySQL/SQLite feature flags.let stored = Language::Ja;let row = sqlx::query!("select $1 as lang", stored).fetch_one(&pool).await?;assert_eq!(row.lang,Language::Ja);If you find this project helpful and would like to support its development, you can buy me a coffee!
Your support is greatly appreciated and motivates me to keep improving this project.
- Fiat
- Crypto
- Bitcoin
bc1pedlrf67ss52md29qqkzr2avma6ghyrt4jx9ecp9457qsl75x247sqcp43c
- Ethereum
0x3e25247CfF03F99a7D83b28F207112234feE73a6
- Polkadot
156HGo9setPcU2qhFMVWLkcmtCEGySLwNqa3DaEiYSWtte4Y
- Bitcoin
Thank you for your support!
We would like to extend our heartfelt gratitude to the following projects and contributors:
- The Rust community for their continuous support and development of the Rust ecosystem.
- translation.io for publishing the languages-with-plural-cases reference we build from.
- Autonym data is downloaded from https://translation.io/docs/languages_with_plural_cases whenever you regenerate code with
cargo run --features codegen --bin language.
Licensed under GPL-3.0.