///|
fn catalog_locale_map(catalogs : Array[Catalog]) -> Map[String, Catalog] {
let output : Map[String, Catalog] = Map([])
for catalog in catalogs {
output[canonicalize_locale_lossy(catalog.locale)] = catalog
}
output
}
///|
fn matrix_locales(catalogs : Array[Catalog]) -> Array[String] {
let locales : Array[String] = []
for catalog in catalogs {
locales.push(canonicalize_locale_lossy(catalog.locale))
}
locales.sort()
locales
}
///|
/// Build a key-presence matrix for a reference and multiple translations.
pub fn catalog_matrix(
reference : Catalog,
translations : Array[Catalog],
) -> CatalogMatrix {
let by_locale = catalog_locale_map(translations)
let locales = matrix_locales(translations)
let rows : Array[CatalogMatrixRow] = []
for key in reference.keys() {
let present_locales : Array[String] = []
let missing_locales : Array[String] = []
for locale in locales {
if by_locale[locale].contains(key) {
present_locales.push(locale)
} else {
missing_locales.push(locale)
}
}
rows.push({ key, present_locales, missing_locales })
}
{
reference_locale: canonicalize_locale_lossy(reference.locale),
locales,
rows,
}
}
///|
pub fn CatalogMatrixRow::key(self : CatalogMatrixRow) -> String {
self.key
}
///|
pub fn CatalogMatrixRow::present_locales(
self : CatalogMatrixRow,
) -> Array[String] {
self.present_locales
}
///|
pub fn CatalogMatrixRow::missing_locales(
self : CatalogMatrixRow,
) -> Array[String] {
self.missing_locales
}
///|
pub fn CatalogMatrixRow::complete(self : CatalogMatrixRow) -> Bool {
self.missing_locales.length() == 0
}
///|
pub fn CatalogMatrixRow::coverage_percent(self : CatalogMatrixRow) -> Int {
let total = self.present_locales.length() + self.missing_locales.length()
if total == 0 {
100
} else {
self.present_locales.length() * 100 / total
}
}
///|
pub fn CatalogMatrix::reference_locale(self : CatalogMatrix) -> String {
self.reference_locale
}
///|
pub fn CatalogMatrix::locales(self : CatalogMatrix) -> Array[String] {
self.locales
}
///|
pub fn CatalogMatrix::rows(self : CatalogMatrix) -> Array[CatalogMatrixRow] {
self.rows
}
///|
pub fn CatalogMatrix::key_count(self : CatalogMatrix) -> Int {
self.rows.length()
}
///|
pub fn CatalogMatrix::locale_count(self : CatalogMatrix) -> Int {
self.locales.length()
}
///|
pub fn CatalogMatrix::has_locale(self : CatalogMatrix, locale : String) -> Bool {
let canonical = canonicalize_locale_lossy(locale)
for available in self.locales {
if available == canonical {
return true
}
}
false
}
///|
pub fn CatalogMatrix::row(
self : CatalogMatrix,
key : String,
) -> CatalogMatrixRow? {
for row in self.rows {
if row.key == key {
return Some(row)
}
}
None
}
///|
pub fn CatalogMatrix::incomplete_rows(
self : CatalogMatrix,
) -> Array[CatalogMatrixRow] {
let output : Array[CatalogMatrixRow] = []
for row in self.rows {
if !row.complete() {
output.push(row)
}
}
output
}
///|
pub fn CatalogMatrix::complete_rows(
self : CatalogMatrix,
) -> Array[CatalogMatrixRow] {
let output : Array[CatalogMatrixRow] = []
for row in self.rows {
if row.complete() {
output.push(row)
}
}
output
}
///|
pub fn CatalogMatrix::missing_keys_for(
self : CatalogMatrix,
locale : String,
) -> Array[String] {
let canonical = canonicalize_locale_lossy(locale)
let output : Array[String] = []
for row in self.rows {
for missing in row.missing_locales {
if missing == canonical {
output.push(row.key)
break
}
}
}
output
}
///|
pub fn CatalogMatrix::present_keys_for(
self : CatalogMatrix,
locale : String,
) -> Array[String] {
let canonical = canonicalize_locale_lossy(locale)
let output : Array[String] = []
for row in self.rows {
for present in row.present_locales {
if present == canonical {
output.push(row.key)
break
}
}
}
output
}
///|
pub fn CatalogMatrix::complete(self : CatalogMatrix) -> Bool {
for row in self.rows {
if !row.complete() {
return false
}
}
true
}
///|
pub fn CatalogMatrix::missing_count(self : CatalogMatrix) -> Int {
let mut count = 0
for row in self.rows {
count += row.missing_locales.length()
}
count
}
///|
pub fn CatalogMatrix::coverage_for(
self : CatalogMatrix,
locale : String,
) -> CatalogCoverage? {
let canonical = canonicalize_locale_lossy(locale)
let mut translated = 0
let mut missing = 0
let mut known = false
for available in self.locales {
if available == canonical {
known = true
break
}
}
if !known {
return None
}
for row in self.rows {
let mut present = false
for available in row.present_locales {
if available == canonical {
present = true
break
}
}
if present {
translated += 1
} else {
missing += 1
}
}
let total = translated + missing
Some({
reference_keys: total,
translated_keys: translated,
missing_keys: missing,
extra_keys: 0,
coverage_percent: if total == 0 {
100
} else {
translated * 100 / total
},
})
}
///|
pub fn CatalogMatrix::to_text(self : CatalogMatrix) -> String {
let output = StringBuilder::new()
output.write_string("reference: ")
output.write_string(self.reference_locale)
output.write_char('\n')
output.write_string("locales: ")
output.write_string(self.locales.join(", "))
output.write_char('\n')
for row in self.rows {
output.write_string(row.key)
output.write_string(" ")
output.write_string(row.coverage_percent().to_string())
output.write_char('%')
if row.missing_locales.length() > 0 {
output.write_string(" missing=")
output.write_string(row.missing_locales.join(","))
}
output.write_char('\n')
}
output.to_string()
}
///|
fn write_matrix_row_json(
output : StringBuilder,
row : CatalogMatrixRow,
) -> Unit {
output.write_char('{')
write_json_string(output, "key")
output.write_char(':')
write_json_string(output, row.key)
output.write_char(',')
write_json_string(output, "coverage_percent")
output.write_char(':')
output.write_string(row.coverage_percent().to_string())
output.write_char(',')
write_json_string(output, "present_locales")
output.write_char(':')
write_string_array_json(output, row.present_locales)
output.write_char(',')
write_json_string(output, "missing_locales")
output.write_char(':')
write_string_array_json(output, row.missing_locales)
output.write_char('}')
}
///|
pub fn CatalogMatrix::to_json(self : CatalogMatrix) -> String {
let output = StringBuilder::new()
output.write_char('{')
write_json_string(output, "reference_locale")
output.write_char(':')
write_json_string(output, self.reference_locale)
output.write_char(',')
write_json_string(output, "locales")
output.write_char(':')
write_string_array_json(output, self.locales)
output.write_char(',')
write_json_string(output, "complete")
output.write_char(':')
output.write_string(if self.complete() { "true" } else { "false" })
output.write_char(',')
write_json_string(output, "missing_count")
output.write_char(':')
output.write_string(self.missing_count().to_string())
output.write_char(',')
write_json_string(output, "rows")
output.write_string(":[")
for index, row in self.rows {
if index > 0 {
output.write_char(',')
}
write_matrix_row_json(output, row)
}
output.write_string("]}")
output.to_string()
}