///|
pub(all) struct ContextSummary {
context : String?
active : Int32
translated : Int32
fuzzy : Int32
plural : Int32
characters : Int32
} derive(Eq, Debug)
///|
pub(all) struct Reference {
path : String
line : Int32?
} derive(Eq, Debug)
///|
/// Split a terminal :line without confusing a Windows drive letter.
pub fn parse_reference(value : String) -> Reference {
let chars = value.to_array()
let mut colon = -1
for i, c in chars {
if c == ':' {
colon = i
}
}
if colon > 0 && colon + 1 < chars.length() {
match
decimal_text(char_slice(chars, colon + 1, chars.length()), 2147483647) {
Some(line) =>
if line > 0 {
return { path: char_slice(chars, 0, colon), line: Some(line), }
}
None => ()
}
}
{ path: value, line: None, }
}
///|
/// Group workload by exact context, retaining null versus empty context.
pub fn context_summaries(catalog : Catalog) -> Array[ContextSummary] {
let positions : Map[String, Int32] = Map([])
let groups : Array[ContextSummary] = []
for entry in catalog.entries {
if entry.obsolete || entry.is_header() {
continue
}
let key = match entry.context {
None => "none"
Some(value) => "some:" + value
}
let position = match positions.get(key) {
Some(position) => position
None => {
let position = groups.length()
positions.set(key, position)
groups.push({
context: entry.context,
active: 0,
translated: 0,
fuzzy: 0,
plural: 0,
characters: 0,
})
position
}
}
let previous = groups[position]
groups[position] = {
context: previous.context,
active: previous.active + 1,
translated: previous.translated +
(if entry.is_translated() { 1 } else { 0 }),
fuzzy: previous.fuzzy + (if entry.has_flag("fuzzy") { 1 } else { 0 }),
plural: previous.plural + (if entry.plural is Some(_) { 1 } else { 0 }),
characters: previous.characters + entry.id.to_array().length(),
}
}
groups
}
///|
pub fn catalog_summary_json(catalog : Catalog) -> Json {
let reference_files : Map[String, Int32] = Map([])
let mut unreferenced = 0
for entry in catalog.entries {
if entry.obsolete || entry.is_header() {
continue
}
if entry.references.is_empty() {
unreferenced += 1
}
let seen : Map[String, Bool] = Map([])
for reference in entry.references {
let path = parse_reference(reference).path
if seen.get(path) is None {
reference_files.set(path, reference_files.get(path).unwrap_or(0) + 1)
seen.set(path, true)
}
}
}
let paths = reference_files.keys().to_array()
paths.sort()
let header = read_header(catalog)
{
"language": optional_json(header.get("Language")),
"project": optional_json(header.get("Project-Id-Version")),
"unreferenced": Json(unreferenced),
"contexts": Json(
context_summaries(catalog).map(group => {
"context": optional_json(group.context),
"active": Json(group.active),
"translated": Json(group.translated),
"fuzzy": Json(group.fuzzy),
"plural": Json(group.plural),
"source_characters": Json(group.characters),
}),
),
"references": Json(
paths.map(path => {
"path": Json(path),
"entries": Json(reference_files.get(path).unwrap_or(0)),
}),
),
}
}