Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

parse

Language tag format expressed as a regular expression (rough approximation):

[a-zA-Z]{1,3}([-_][a-zA-Z]{4})?([-_][a-zA-Z]{2})?([-_][a-zA-Z0-9]{1,8})? lang | script | country | suffix

Notes:

lang.parse
pub fn parse(lang_tag: []const u8) error

File

Code

pub fn parse(lang_tag: []const u8) error{InvalidLanguageTag}!Parsed {
    var it = std.mem.splitAny(u8, lang_tag, "-_");
    const lang_code = it.first();
    const is_valid_lang_code = lang_code.len >= 1 and lang_code.len <= 3 and isAllAlphabetic(lang_code);
    if (!is_valid_lang_code) return error.InvalidLanguageTag;
    var parsed = Parsed{
        .language_code = lang_code,
    };
    // The second part could be a script tag, a country code, or a suffix
    if (it.next()) |part_str| {
        // The lang code being length 1 behaves strangely, so fully special case it.
        if (lang_code.len == 1) {
            // This is almost certainly not the 'right' way to do this, but I don't have a method
            // to determine how exactly these language tags are parsed, and it seems like
            // suffix parsing rules apply generally (digits allowed, length of 1 to 8).
            //
            // However, because we want to be able to lookup `x-iv-mathan` normally without
            // `multiple_suffixes` being set to true, we need to make sure to treat two-length
            // alphabetic parts as a country code.
            if (part_str.len == 2 and isAllAlphabetic(part_str)) {
                parsed.country_code = part_str;
            }
            // Everything else, though, we can just throw into the suffix as long as the normal
            // rules apply.
            else if (part_str.len > 0 and part_str.len <= 8 and isAllAlphanumeric(part_str)) {
                parsed.suffix = part_str;
            } else {
                return error.InvalidLanguageTag;
            }
        } else if (part_str.len == 4 and isAllAlphabetic(part_str)) {
            parsed.script_tag = part_str;
        } else if (part_str.len == 2 and isAllAlphabetic(part_str)) {
            parsed.country_code = part_str;
        }
        // Only a 3-len numeric suffix is allowed as the second part of a tag
        else if (part_str.len == 3 and isAllNumeric(part_str)) {
            parsed.suffix = part_str;
        }
        // Special case for qps-ploca and qps-plocm
        else if (std.ascii.eqlIgnoreCase(lang_code, "qps") and
            (std.ascii.eqlIgnoreCase(part_str, "ploca") or
                std.ascii.eqlIgnoreCase(part_str, "plocm")))
        {
            parsed.suffix = part_str;
        } else {
            return error.InvalidLanguageTag;
        }
    } else {
        // If there's no part besides a 1-len lang code, then it is malformed
        if (lang_code.len == 1) return error.InvalidLanguageTag;
        return parsed;
    }
    if (parsed.script_tag != null) {
        if (it.next()) |part_str| {
            if (part_str.len == 2 and isAllAlphabetic(part_str)) {
                parsed.country_code = part_str;
            } else {
                // Suffix is not allowed when a country code is not present.
                return error.InvalidLanguageTag;
            }
        } else {
            return parsed;
        }
    }
    // We've now parsed any potential script tag/country codes, so anything remaining
    // is a suffix
    while (it.next()) |part_str| {
        if (part_str.len == 0 or part_str.len > 8 or !isAllAlphanumeric(part_str)) {
            return error.InvalidLanguageTag;
        }
        if (parsed.suffix == null) {
            parsed.suffix = part_str;
        } else {
            // In theory we could return early here but we still want to validate
            // that each part is a valid suffix all the way to the end, e.g.
            // we should reject `en-us-suffix-a-b-c-!!!` because of the invalid `!!!`
            // suffix part.
            parsed.multiple_suffixes = true;
        }
    }
    return parsed;
}