@@ -35,8 +35,8 @@ unittest {
35
35
import vibe.web.web : registerWebInterface;
36
36
37
37
struct TranslationContext {
38
- import std.typetuple ;
39
- alias languages = TypeTuple ! (" en_US" , " de_DE" , " fr_FR" );
38
+ import std.meta : AliasSeq ;
39
+ alias languages = AliasSeq ! (" en_US" , " de_DE" , " fr_FR" );
40
40
// mixin translationModule!"app";
41
41
// mixin translationModule!"somelib";
42
42
}
@@ -62,9 +62,9 @@ unittest {
62
62
import vibe.web.web : registerWebInterface;
63
63
64
64
struct TranslationContext {
65
- import std.typetuple ;
65
+ import std.meta : AliasSeq ;
66
66
// A language can be in the form en_US, en-US or en. Put the languages you want to prioritize first.
67
- alias languages = TypeTuple ! (" en_US" , " de_DE" , " fr_FR" );
67
+ alias languages = AliasSeq ! (" en_US" , " de_DE" , " fr_FR" );
68
68
// mixin translationModule!"app";
69
69
// mixin translationModule!"somelib";
70
70
@@ -97,8 +97,8 @@ unittest {
97
97
import vibe.web.web : registerWebInterface;
98
98
99
99
struct TranslationContext {
100
- import std.typetuple ;
101
- alias languages = TypeTuple ! (" en_US" , " de_DE" , " fr_FR" );
100
+ import std.meta : AliasSeq ;
101
+ alias languages = AliasSeq ! (" en_US" , " de_DE" , " fr_FR" );
102
102
static string determineLanguage (scope HTTPServerRequest req) { return " en_US" ; }
103
103
}
104
104
@@ -143,14 +143,14 @@ html
143
143
144
144
See_Also: `translationContext`
145
145
*/
146
- mixin template translationModule(string FILENAME )
146
+ mixin template translationModule(string FILENAME , string language_separator = " . " )
147
147
{
148
- import std.string : tr ;
149
- enum NAME = FILENAME . tr(` /.-\ ` , " ____" );
148
+ static import std.string ;
149
+ enum NAME = std.string. tr (FILENAME , ` /.\\- ` , " ____" );
150
150
private static string file_mixins () {
151
151
string ret;
152
152
foreach (language; languages)
153
- ret ~= " enum " ~ language~ " _" ~ NAME ~ " = extractDeclStrings(import(`" ~ FILENAME ~ " . " ~ language~ " .po`));\n " ;
153
+ ret ~= " enum " ~ language~ " _" ~ NAME ~ " = extractDeclStrings(import(`" ~ FILENAME ~ language_separator ~ language~ " .po`));\n " ;
154
154
return ret;
155
155
}
156
156
@@ -482,11 +482,15 @@ LangComponents extractDeclStrings(string text)
482
482
assert (text.length - i >= 6 && text[i .. i+ 6 ] == " msgstr" , " Expected 'msgstr', got '" ~ text[i .. min(i+ 10 , $)]~ " '." );
483
483
i += 6 ;
484
484
485
- i = skipWhitespace(i, text);
486
- auto ivnext = skipString(i, text);
487
- auto value = dstringUnescape(wrapText(text[i+ 1 .. ivnext- 1 ]));
488
- i = ivnext;
489
- i = skipToDirective(i, text);
485
+ string value;
486
+ if (text[i] == ' [' ) i -= 6 ;
487
+ else {
488
+ i = skipWhitespace(i, text);
489
+ auto ivnext = skipString(i, text);
490
+ value = dstringUnescape(wrapText(text[i+ 1 .. ivnext- 1 ]));
491
+ i = ivnext;
492
+ i = skipToDirective(i, text);
493
+ }
490
494
491
495
// msgstr[n] is a required field when msgid_plural is not null, and ignored otherwise
492
496
string [] value_plural;
@@ -650,9 +654,9 @@ msgstr "Third letter"
650
654
enum components = extractDeclStrings(str);
651
655
652
656
struct TranslationContext {
653
- import std.typetuple ;
657
+ import std.meta : AliasSeq ;
654
658
enum enforceExistingKeys = true ;
655
- alias languages = TypeTuple ! (" en_US" );
659
+ alias languages = AliasSeq ! (" en_US" );
656
660
657
661
// Note that this is normally handled by mixing in an external file.
658
662
enum en_US_unittest = components;
@@ -684,15 +688,20 @@ msgid_plural "Several files were created."
684
688
msgstr "One file was created."
685
689
msgstr[0] "1 file was created"
686
690
msgstr[1] "%d files were created."
691
+
692
+ msgid "One file was modified."
693
+ msgid_plural "Several files were modified."
694
+ msgstr[0] "One file was modified."
695
+ msgstr[1] "%d files were modified."
687
696
` ;
688
697
689
698
import std.stdio ;
690
699
enum components = extractDeclStrings(str);
691
700
692
701
struct TranslationContext {
693
- import std.typetuple ;
702
+ import std.meta : AliasSeq ;
694
703
enum enforceExistingKeys = true ;
695
- alias languages = TypeTuple ! (" en_US" );
704
+ alias languages = AliasSeq ! (" en_US" );
696
705
697
706
// Note that this is normally handled by mixing in an external file.
698
707
enum en_US_unittest2 = components;
@@ -738,7 +747,7 @@ private size_t skipLine(size_t i, ref string text)
738
747
private size_t skipString (size_t i, ref string text)
739
748
{
740
749
import std.conv : to;
741
- assert (text[i] == ' "' , " Expected to encounter the start of a string at position: " ~ to ! string (i ));
750
+ assert (text[i] == ' "' , " Expected to encounter the start of a string at position: " ~ locationString(i, text ));
742
751
i++ ;
743
752
while (true ) {
744
753
assert (i < text.length, " Missing closing '\" ' for string: " ~ text[i .. min($, 10 )]);
@@ -756,7 +765,7 @@ private size_t skipString(size_t i, ref string text)
756
765
757
766
private size_t skipIndex (size_t i, ref string text) {
758
767
import std.conv : to;
759
- assert (text[i] == ' [' , " Expected to encounter a plural form of msgstr at position: " ~ to ! string (i ));
768
+ assert (text[i] == ' [' , " Expected to encounter a plural form of msgstr at position: " ~ locationString(i, text ));
760
769
for (; i< text.length; ++ i) {
761
770
if (text[i] == ' ]' ) {
762
771
return i+ 1 ;
@@ -865,3 +874,15 @@ private string dstringUnescape(in string str)
865
874
}
866
875
return ret;
867
876
}
877
+
878
+ private string locationString (size_t i, string text)
879
+ {
880
+ import std.algorithm.searching : count;
881
+ import std.format : format;
882
+ import std.string : lastIndexOf;
883
+
884
+ auto ln = text[0 .. i].count(' \n ' );
885
+ auto sep = text[0 .. i].lastIndexOf(' \n ' );
886
+ auto col = sep >= 0 ? i - sep - 1 : i;
887
+ return format (" line %s, column %s" , ln+ 1 , col+ 1 );
888
+ }
0 commit comments