🌍 Lang
Represent languages in Gleam!
Lang provides a Language type representing the ISO 639 languages that have both two-letter (ISO 639-1) and three-letter (ISO 639-2) codes, with helper functions to work with them.
This is designed to be a minimal foundational library so that different libraries and applications can interoperate with a common Language type.
gleam add lang@1
import gleam/io
import gleam/list
import gleam/string
import lang
pub fn main() {
let language = lang.En
lang.to_iso639_1(language)
// -> "en"
lang.to_iso639_2(language)
// -> "eng"
lang.to_name(language)
// -> "English"
case lang.from_iso639_1("KO") {
Ok(korean) -> {
io.println("Language: " <> lang.to_name(korean))
// -> "Language: Korean"
}
Error(_) -> io.println("Unknown language code")
}
let assert Ok(german_terminological) = lang.from_iso639_2("deu")
let assert Ok(german_bibliographic) = lang.from_iso639_2("ger")
// Both return the same language (lang.De)
german_terminological == german_bibliographic
// -> True
// Iterate over all languages
lang.all
|> list.filter(fn(l) { lang.to_iso639_1(l) |> string.starts_with("a") })
|> list.map(lang.to_name)
// -> ["Afar", "Abkhazian", "Afrikaans", "Akan", ..]
}
Design Philosophy
Lang is intentionally minimal:
- Provides ISO 639-1 and ISO 639-2 language identification
- Keeps the surface area small by not modelling regional variants (
en-US,en-GB) - Stays focused by excluding script information (
zh-Hans,zh-Hant) - Avoids complexity such as translations or localisation
These choices keep the library lean, leaving additional functionality to application code or higher-level libraries.
ISO 639-2 Bibliographic vs. Terminological Codes
Some languages have two ISO 639-2 codes:
- Terminological (T) - Modern canonical form e.g.
deufor German - Bibliographic (B) - Used in libraries/catalogs e.g.
gerfor German
// to_iso639_2 returns the T code (or the B code if no T code exists)
lang.to_iso639_2(lang.En) // "eng"
lang.to_iso639_2(lang.De) // "deu" (not "ger")
lang.to_iso639_2(lang.Zh) // "zho" (not "chi")
// from_iso639_2 accepts both bibliographic and terminological codes
lang.from_iso639_2("deu") // Ok(De)
lang.from_iso639_2("ger") // Ok(De) - same result
Examples
The following are some examples to demonstrate how you might use lang.
Content Management System with Regional Variants
import lang.{type Language}
pub type ContentLocale {
ContentLocale(language: Language, region: String)
}
// Define your locales
pub const en_us = ContentLocale(lang.En, "US")
pub const en_gb = ContentLocale(lang.En, "GB")
pub const pt_br = ContentLocale(lang.Pt, "BR")
pub const pt_pt = ContentLocale(lang.Pt, "PT")
pub fn format_date(date: Date, locale: ContentLocale) -> String {
case locale.language, locale.region {
lang.En, "US" -> format_us_date(date)
lang.En, "GB" -> format_uk_date(date)
lang.Pt, "BR" -> format_br_date(date)
lang.Pt, "PT" -> format_pt_date(date)
language, _ -> format_default_date(date, language)
}
}
HTTP Headers
import gleam/http/request
import gleam/http/response
import gleam/list
import gleam/result
import gleam/string
import lang.{type Language}
pub fn set_content_language(
resp: response.Response(a),
language: Language,
) -> response.Response(a) {
response.set_header(resp, "content-language", lang.to_iso639_1(language))
}
pub fn get_accept_language(req: request.Request(a)) -> Result(Language, Nil) {
let fallback = lang.En
// Parse "en-US,en;q=0.9,es;q=0.8" -> "en"
request.get_header(req, "accept-language")
|> result.unwrap(lang.to_iso639_1(fallback))
|> string.split(",")
|> list.first
|> result.try(fn(first) {
first
|> string.split("-")
|> list.first
})
|> result.try(lang.from_iso639_1)
|> result.unwrap(fallback)
|> Ok
}
Multilingual CLI Application
import argv
import gleam/io
import gleam/list
import gleam/result
import gleam/string
import lang.{type Language}
pub fn main() {
let language =
argv.load().arguments
|> list.find(fn(arg) { string.starts_with(arg, "--lang=") })
|> result.map(fn(arg) { string.drop_start(arg, 7) })
|> result.try(lang.from_iso639_1)
|> result.unwrap(get_system_language())
print_welcome(language)
}
fn print_welcome(language: Language) {
case language {
lang.En -> io.println("Welcome!")
lang.Es -> io.println("¡Bienvenido!")
lang.Fr -> io.println("Bienvenue!")
lang.De -> io.println("Willkommen!")
lang.Ja -> io.println("ようこそ!")
lang.Tw -> io.println("Akwaaba!")
lang.Zh -> io.println("欢迎!")
_ -> io.println("Welcome!")
}
}
fn get_system_language() -> Language {
todo as "Implementation would check LANG environment variable"
}
Development
This library is code-generated from the official ISO 639 data.
The language-codes-full.csv file is available on DataHub.
The code generation modules along with the CSV file are located in dev/.
After making changes, run the following:
gleam run -m codegen # Regenerate src/lang module
gleam build # Build the package
gleam docs build # Build docs
gleam test # Run the tests
If the languages-codes-full.csv file is re-downloaded, update the date in dev/INFO.md.