Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web t9n improvements #2805

Merged
merged 5 commits into from
Oct 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 42 additions & 21 deletions web/vibe/web/i18n.d
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Expand All @@ -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";

Expand Down Expand Up @@ -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"; }
}

Expand Down Expand Up @@ -143,14 +143,14 @@ html

See_Also: `translationContext`
*/
mixin template translationModule(string FILENAME)
mixin template translationModule(string FILENAME, string language_separator = ".")
{
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)
ret ~= "enum "~language~"_"~NAME~" = extractDeclStrings(import(`"~FILENAME~"."~language~".po`));\n";
ret ~= "enum "~language~"_"~NAME~" = extractDeclStrings(import(`"~FILENAME~language_separator~language~".po`));\n";
return ret;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -650,9 +654,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;
Expand Down Expand Up @@ -684,15 +688,20 @@ 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;
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;
Expand Down Expand Up @@ -738,7 +747,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)]);
Expand All @@ -756,7 +765,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<text.length; ++i) {
if (text[i] == ']') {
return i+1;
Expand Down Expand Up @@ -865,3 +874,15 @@ private string dstringUnescape(in string str)
}
return ret;
}

private string locationString(size_t i, string text)
{
import std.algorithm.searching : count;
import std.format : format;
import std.string : lastIndexOf;

auto ln = text[0 .. i].count('\n');
auto sep = text[0 .. i].lastIndexOf('\n');
auto col = sep >= 0 ? i - sep - 1 : i;
return format("line %s, column %s", ln+1, col+1);
}
Loading