From c030cf5bdefebbb772c46ba3a10981a029f43478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 30 Sep 2024 21:15:50 +0200 Subject: [PATCH 1/5] Use AliasSeq instead of TypeTuple. --- web/vibe/web/i18n.d | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/web/vibe/web/i18n.d b/web/vibe/web/i18n.d index 6227b7dc52..3e51d9d66e 100644 --- a/web/vibe/web/i18n.d +++ b/web/vibe/web/i18n.d @@ -35,8 +35,8 @@ unittest { import vibe.web.web : registerWebInterface; struct TranslationContext { - import std.typetuple; - alias languages = TypeTuple!("en_US", "de_DE", "fr_FR"); + import std.meta : AliasSeq; + alias languages = AliasSeq!("en_US", "de_DE", "fr_FR"); //mixin translationModule!"app"; //mixin translationModule!"somelib"; } @@ -62,9 +62,9 @@ unittest { import vibe.web.web : registerWebInterface; struct TranslationContext { - import std.typetuple; + import std.meta : AliasSeq; // A language can be in the form en_US, en-US or en. Put the languages you want to prioritize first. - alias languages = TypeTuple!("en_US", "de_DE", "fr_FR"); + alias languages = AliasSeq!("en_US", "de_DE", "fr_FR"); //mixin translationModule!"app"; //mixin translationModule!"somelib"; @@ -97,8 +97,8 @@ unittest { import vibe.web.web : registerWebInterface; struct TranslationContext { - import std.typetuple; - alias languages = TypeTuple!("en_US", "de_DE", "fr_FR"); + import std.meta : AliasSeq; + alias languages = AliasSeq!("en_US", "de_DE", "fr_FR"); static string determineLanguage(scope HTTPServerRequest req) { return "en_US"; } } @@ -650,9 +650,9 @@ msgstr "Third letter" enum components = extractDeclStrings(str); struct TranslationContext { - import std.typetuple; + import std.meta : AliasSeq; enum enforceExistingKeys = true; - alias languages = TypeTuple!("en_US"); + alias languages = AliasSeq!("en_US"); // Note that this is normally handled by mixing in an external file. enum en_US_unittest = components; @@ -690,9 +690,9 @@ msgstr[1] "%d files were created." enum components = extractDeclStrings(str); struct TranslationContext { - import std.typetuple; + import std.meta : AliasSeq; enum enforceExistingKeys = true; - alias languages = TypeTuple!("en_US"); + alias languages = AliasSeq!("en_US"); // Note that this is normally handled by mixing in an external file. enum en_US_unittest2 = components; From d93c88d7bc566395031a9da10f149f9319c1eac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 30 Sep 2024 21:16:30 +0200 Subject: [PATCH 2/5] Print line/colum instead of byte offsets for PO file parsing errors. --- web/vibe/web/i18n.d | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/web/vibe/web/i18n.d b/web/vibe/web/i18n.d index 3e51d9d66e..6326e7db6b 100644 --- a/web/vibe/web/i18n.d +++ b/web/vibe/web/i18n.d @@ -738,7 +738,7 @@ private size_t skipLine(size_t i, ref string text) private size_t skipString(size_t i, ref string text) { import std.conv : to; - assert(text[i] == '"', "Expected to encounter the start of a string at position: "~to!string(i)); + assert(text[i] == '"', "Expected to encounter the start of a string at position: "~locationString(i, text)); i++; while (true) { assert(i < text.length, "Missing closing '\"' for string: "~text[i .. min($, 10)]); @@ -756,7 +756,7 @@ private size_t skipString(size_t i, ref string text) private size_t skipIndex(size_t i, ref string text) { import std.conv : to; - assert(text[i] == '[', "Expected to encounter a plural form of msgstr at position: "~to!string(i)); + assert(text[i] == '[', "Expected to encounter a plural form of msgstr at position: "~locationString(i, text)); for (; i= 0 ? i - sep - 1 : i; + return format("line %s, column %s", ln+1, col+1); +} From 5a8a12bc6305af972df8066d3f5661582db78afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 30 Sep 2024 21:17:01 +0200 Subject: [PATCH 3/5] Fix parsing plural translations with only msgstr[*] entries. --- web/vibe/web/i18n.d | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/web/vibe/web/i18n.d b/web/vibe/web/i18n.d index 6326e7db6b..78f09cd1ed 100644 --- a/web/vibe/web/i18n.d +++ b/web/vibe/web/i18n.d @@ -482,11 +482,15 @@ LangComponents extractDeclStrings(string text) assert(text.length - i >= 6 && text[i .. i+6] == "msgstr", "Expected 'msgstr', got '"~text[i .. min(i+10, $)]~"'."); i += 6; - i = skipWhitespace(i, text); - auto ivnext = skipString(i, text); - auto value = dstringUnescape(wrapText(text[i+1 .. ivnext-1])); - i = ivnext; - i = skipToDirective(i, text); + string value; + if (text[i] == '[') i -= 6; + else { + i = skipWhitespace(i, text); + auto ivnext = skipString(i, text); + value = dstringUnescape(wrapText(text[i+1 .. ivnext-1])); + i = ivnext; + i = skipToDirective(i, text); + } // msgstr[n] is a required field when msgid_plural is not null, and ignored otherwise string[] value_plural; @@ -684,6 +688,11 @@ msgid_plural "Several files were created." msgstr "One file was created." msgstr[0] "1 file was created" msgstr[1] "%d files were created." + +msgid "One file was modified." +msgid_plural "Several files were modified." +msgstr[0] "One file was modified." +msgstr[1] "%d files were modified." `; import std.stdio; From 64015306c3c2e8166b37b5bba815160cc37b6a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 30 Sep 2024 21:18:20 +0200 Subject: [PATCH 4/5] Fix replacing non-identifier characters in translation module names. Avoids compile errors for modules like "foo-bar.en_US.po". --- web/vibe/web/i18n.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/vibe/web/i18n.d b/web/vibe/web/i18n.d index 78f09cd1ed..4c7e813cdc 100644 --- a/web/vibe/web/i18n.d +++ b/web/vibe/web/i18n.d @@ -145,8 +145,8 @@ html */ mixin template translationModule(string FILENAME) { - import std.string : tr; - enum NAME = FILENAME.tr(`/.-\`, "____"); + static import std.string; + enum NAME = std.string.tr(FILENAME, `/.\\-`, "____"); private static string file_mixins() { string ret; foreach (language; languages) From d17211f48a7ef7718da8d4c00d328830b5aeece3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6nke=20Ludwig?= Date: Mon, 30 Sep 2024 21:19:03 +0200 Subject: [PATCH 5/5] Allow customizing the separator used in .po file names. --- web/vibe/web/i18n.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/vibe/web/i18n.d b/web/vibe/web/i18n.d index 4c7e813cdc..821a7982b6 100644 --- a/web/vibe/web/i18n.d +++ b/web/vibe/web/i18n.d @@ -143,14 +143,14 @@ html See_Also: `translationContext` */ -mixin template translationModule(string FILENAME) +mixin template translationModule(string FILENAME, string language_separator = ".") { static import std.string; enum NAME = std.string.tr(FILENAME, `/.\\-`, "____"); private static string file_mixins() { string ret; foreach (language; languages) - ret ~= "enum "~language~"_"~NAME~" = extractDeclStrings(import(`"~FILENAME~"."~language~".po`));\n"; + ret ~= "enum "~language~"_"~NAME~" = extractDeclStrings(import(`"~FILENAME~language_separator~language~".po`));\n"; return ret; }