7#include "po_translations.hpp"
8#include "../i18n/i18n.hpp"
10#include "../parser/parser.hpp"
11#include "../macros.hpp"
17hi_export_module(hikogui.l10n.po_parser);
19hi_export
namespace hi {
inline namespace v1 {
23template<std::input_iterator It, std::sentinel_for<It> ItEnd>
26 hi_assert(
it != last);
29 if ((*
it == token::id)) {
33 std::format(
"{}: Expecting a keyword at start of each line, got {}",
token_location(
it, last, path), *
it));
40 if (
it != last
and *
it == token::integer) {
41 index =
static_cast<size_t>(*
it++);
43 throw parse_error(std::format(
44 "{}: Expecting an integer literal as an index for {}, got {}",
token_location(
it, last, path), name, *
it));
47 if (
it != last
and *
it ==
']') {
50 throw parse_error(std::format(
51 "{}: The index on {} must terminate with a bracket ']', got {}",
token_location(
it, last, path), name, *
it));
56 if (
it != last
and (*
it == token::sstr
or *
it == token::dstr)) {
60 std::format(
"{}: Expecting a string value after {}, got {}",
token_location(
it, last, path), name, *
it));
63 while (
it != last
and (*
it == token::sstr
or *
it == token::dstr)) {
68 return {name, index, value};
71template<std::input_iterator It, std::sentinel_for<It> ItEnd>
72[[
nodiscard]]
constexpr std::optional<po_translation> parse_po_translation(
It&
it, ItEnd last, std::string_view path)
77 if (r.msgstr.empty()) {
79 auto [name, index, value] = parse_po_line(
it, last, path);
81 if (name ==
"msgctxt") {
84 }
else if (name ==
"msgid") {
87 }
else if (name ==
"msgid_plural") {
88 r.msgid_plural = value;
90 }
else if (name ==
"msgstr") {
91 if (index >= r.msgstr.size()) {
92 r.msgstr.resize(index + 1);
94 r.msgstr[index] = value;
98 std::format(
"{}: Line starts with unexpected keyword {}",
token_location(
it, last, path), name));
101 }
else if ((*
it == token::id)
and (*
it ==
"msgstr")) {
103 auto [name, index, value] = parse_po_line(
it, last, path);
105 if (index >= r.msgstr.size()) {
106 r.msgstr.resize(index + 1);
108 r.msgstr[index] = value;
121 using namespace std::literals;
131 throw parse_error(std::format(
"Unknown header '{}'", std::string_view{line}));
134 auto const name = to_lower(strip(
split_line.front()));
136 auto const value = strip(join(
split_line,
":"));
138 if (name ==
"language") {
139 r.language = language_tag{value};
146template<std::input_iterator It, std::sentinel_for<It> ItEnd>
151 auto token_it = lexer<lexer_config::sh_style()>.parse(
it, last);
153 while (
token_it != std::default_sentinel) {
154 if (
auto result = detail::parse_po_translation(
token_it, std::default_sentinel, path)) {
156 r.translations.push_back(*
result);
158 }
else if (
result->msgstr.size() == 1) {
160 detail::parse_po_header(r,
result->msgstr.front());
173 return parse_po(text.begin(), text.end(), path);
178 return parse_po(as_string_view(file_view{path}), path.string());
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
The HikoGUI namespace.
Definition recursive_iterator.hpp:15
hi_export constexpr std::string token_location(It &it, ItEnd last, std::string_view path) noexcept
Create a location string for error messages.
Definition token.hpp:163
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:378