summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2015-08-15 13:46:15 +0200
committerYorhel <git@yorhel.nl>2015-08-15 13:46:15 +0200
commit295ccf2ef58898b1cbee32a137ae859d67237a3a (patch)
tree2f7fd478ad13da179830e7b63dc35cd29e401920
parent8c1c8311f5910d8bf62eee449c20d87b62412239 (diff)
js: Let jsgen.pl preprocess L10N strings + add L10N strings to some vars
This simplifies the JS version of mt() a bit and makes the whole internationalization framework a bit more robust. I also changed the VARS.{rlist_status,age_ratings,languages,platforms,char_roles} arrays to include the L10N string. This simplifies the JS code and reduces the JS size. There's a few more of such lists that can be transformed in the same way, I'll get to that later.
-rw-r--r--data/global.pl2
-rw-r--r--data/js/charvns.js4
-rw-r--r--data/js/filter.js31
-rw-r--r--data/js/lib.js22
-rw-r--r--data/js/misc.js2
-rw-r--r--data/js/vnreldropdown.js21
-rwxr-xr-xutil/jsgen.pl66
7 files changed, 77 insertions, 71 deletions
diff --git a/data/global.pl b/data/global.pl
index ef368d61..c8f2537b 100644
--- a/data/global.pl
+++ b/data/global.pl
@@ -106,7 +106,7 @@ our %S = (%S,
voiced => [ 0..4 ],
animated => [ 0..4 ],
wishlist_status => [ 0..3 ],
- rlist_status => [ 0..4 ], # 2 = hardcoded 'OK'
+ rlist_status => [ 0..4 ], # 0 = hardcoded "unknown", 2 = hardcoded 'OK'. List must not have gaps
vnlist_status => [ 0..4 ],
blood_types => [qw| unknown o a b ab |],
genders => [qw| unknown m f b |],
diff --git a/data/js/charvns.js b/data/js/charvns.js
index e1251dcb..10fd1f77 100644
--- a/data/js/charvns.js
+++ b/data/js/charvns.js
@@ -77,8 +77,8 @@ function cvnRelAdd(vid, rid, role, spoil) {
}
var lsel = tag('select', {onchange:cvnSerialize});
- for(var i=0; i<VARS.char_roles.length; i++) // l10n /^_charrole_/
- lsel.appendChild(tag('option', {value: VARS.char_roles[i], selected:VARS.char_roles[i]==role}, mt('_charrole_'+VARS.char_roles[i])));
+ for(var i=0; i<VARS.char_roles.length; i++)
+ lsel.appendChild(tag('option', {value: VARS.char_roles[i][0], selected:VARS.char_roles[i][0]==role}, VARS.char_roles[i][1]));
// l10n /_spoil_\d+/
var ssel = tag('select', {onchange:cvnSerialize});
diff --git a/data/js/filter.js b/data/js/filter.js
index 6975b7c4..36a32e50 100644
--- a/data/js/filter.js
+++ b/data/js/filter.js
@@ -442,9 +442,6 @@ function filChars() {
var bloodt = VARS.blood_types;
for(var i=0; i<bloodt.length; i++) // l10n /_bloodt_.+/
bloodt[i] = [ bloodt[i], bloodt[i] == 'unknown' ? mt('_unknown') : mt('_bloodt_'+bloodt[i]) ];
- var roles = VARS.char_roles;
- for(var i=0; i<roles.length; i++) // l10n /_charrole_.+/
- roles[i] = [ roles[i], mt('_charrole_'+roles[i]) ];
var ontraitpage = location.pathname.indexOf('/c/') < 0;
@@ -474,7 +471,7 @@ function filChars() {
filFTagInput('trait_exc', mt('_charb_traitexc'), 'trait'),
filFOptions('tagspoil', ' ', [[0, mt('_spoilset_0')],[1, mt('_spoilset_1')],[2, mt('_spoilset_2')]]),
],
- [ mt('_charb_roles'), filFSelect('role', mt('_charb_roles'), 4, roles) ]
+ [ mt('_charb_roles'), filFSelect('role', mt('_charb_roles'), 4, VARS.char_roles) ]
];
}
@@ -482,15 +479,7 @@ function filReleases() {
var types = VARS.release_types;
for(var i=0; i<types.length; i++) // l10n /_rtype_.+/
types[i] = [ types[i], mt('_rtype_'+types[i]) ];
- var ages = VARS.age_ratings;
- for(var i=0; i<ages.length; i++)
- ages[i] = [ ages[i], ages[i] == -1 ? mt('_unknown') : ages[i] == 0 ? mt('_minage_all') : mt('_minage_age', ages[i]) ];
- var lang = VARS.languages;
- for(var i=0; i<lang.length; i++) // l10n /_lang_.+/
- lang[i] = [ lang[i], mt('_lang_'+lang[i]) ];
var plat = VARS.platforms;
- for(var i=0; i<plat.length; i++) // l10n /_plat_.+/
- plat[i] = [ plat[i], mt('_plat_'+plat[i]) ];
plat.splice(0, 0, [ 'unk', mt('_unknown') ]);
var med = VARS.media;
for(var i=0; i<med.length; i++) // l10n /_med_.+/
@@ -513,9 +502,9 @@ function filReleases() {
[ 'date_before', mt('_rbrowse_datebefore'), dateLoad(null, filSelectField), function (c) { return [c.date_val] }, function(o,v) { o.dateSet(v) } ],
filFOptions('released', mt('_rbrowse_released'),[ [1, mt('_rbrowse_released_yes')], [0, mt('_rbrowse_released_no')] ])
],
- [ mt('_rbrowse_minage'), filFSelect('minage', mt('_rbrowse_minage'), 15, ages) ],
- [ mt('_rbrowse_language'), filFSelect('lang', mt('_rbrowse_language'), 20, lang) ],
- [ mt('_rbrowse_olang'), filFSelect('olang', mt('_rbrowse_olang'), 20, lang) ],
+ [ mt('_rbrowse_minage'), filFSelect('minage', mt('_rbrowse_minage'), 15, VARS.age_ratings) ],
+ [ mt('_rbrowse_language'), filFSelect('lang', mt('_rbrowse_language'), 20, VARS.languages) ],
+ [ mt('_rbrowse_olang'), filFSelect('olang', mt('_rbrowse_olang'), 20, VARS.languages) ],
[ mt('_rbrowse_resolution'), filFSelect('resolution', mt('_rbrowse_resolution'), 15, VARS.resolutions) ],
[ mt('_rbrowse_platform'), filFSelect('plat', mt('_rbrowse_platform'), 20, plat) ],
[ mt('_rbrowse_medium'), filFSelect('med', mt('_rbrowse_medium'), 10, med) ],
@@ -528,12 +517,6 @@ function filReleases() {
}
function filVN() {
- var lang = VARS.languages;
- for(var i=0; i<lang.length; i++) // l10n /_lang_.+/
- lang[i] = [ lang[i], mt('_lang_'+lang[i]) ];
- var plat = VARS.platforms;
- for(var i=0; i<plat.length; i++) // l10n /_plat_.+/
- plat[i] = [ plat[i], mt('_plat_'+plat[i]) ];
var len = VARS.vn_lengths;
for(var i=0; i<len.length; i++) // l10n /_vnlength_.+/
len[i] = [ len[i], len[i] == 0 ? mt('_unknown') : mt('_vnlength_'+len[i]) ];
@@ -555,9 +538,9 @@ function filVN() {
filFTagInput('tag_exc', mt('_vnbrowse_tagexc'), 'tag'),
filFOptions('tagspoil', ' ', [[0, mt('_spoilset_0')],[1, mt('_spoilset_1')],[2, mt('_spoilset_2')]])
],
- [ mt('_vnbrowse_language'), filFSelect('lang', mt('_vnbrowse_language'), 20, lang) ],
- [ mt('_vnbrowse_olang'), filFSelect('olang',mt('_vnbrowse_olang'), 20, lang) ],
- [ mt('_vnbrowse_platform'), filFSelect('plat', mt('_vnbrowse_platform'), 20, plat) ],
+ [ mt('_vnbrowse_language'), filFSelect('lang', mt('_vnbrowse_language'), 20, VARS.languages) ],
+ [ mt('_vnbrowse_olang'), filFSelect('olang',mt('_vnbrowse_olang'), 20, VARS.languages) ],
+ [ mt('_vnbrowse_platform'), filFSelect('plat', mt('_vnbrowse_platform'), 20, VARS.platforms) ],
!byId('pref_code') ? null : [
mt('_vnbrowse_ul'),
filFOptions('ul_notblack', mt('_vnbrowse_ul_notblack'), [[1, mt('_vnbrowse_ul_notblackmsg')]]),
diff --git a/data/js/lib.js b/data/js/lib.js
index 8e79f37a..72925a93 100644
--- a/data/js/lib.js
+++ b/data/js/lib.js
@@ -167,22 +167,16 @@ window.shorten = function(v, l) {
};
-/* maketext function, less powerful than the Perl equivalent:
- * - Only supports [_n], ~[, ~]
- * - When it finds [quant,_n,..], it will only return the first argument (and doesn't support ~ in an argument)
- */
+/* maketext function. Less powerful than the Perl equivalent, as it only
+ * supports [_n], ~[ and ~]. jsgen.pl is responsible for weeding out the other
+ * codes. */
window.mt = function() {
var key = arguments[0];
- var val = VARS.l10n_str[key] ? VARS.l10n_str[key] : key;
- for(var i=1; i<arguments.length; i++) {
- var expr = '[_'+i+']';
- while(val.indexOf(expr) >= 0)
- val = val.replace(expr, arguments[i]);
- }
- val = val.replace(/\[quant,_\d+\,([^,]+)[^\]]+\]/g, "$1");
- while(val.indexOf('~[') >= 0 || val.indexOf('~]') >= 0)
- val = val.replace('~[', '[').replace('~]', ']');
- return val;
+ var val = VARS.l10n_str[key] || key;
+ // BUG: ~[_1] will get replaced. We don't have a string like that, so whatever.
+ for(var i=1; i<arguments.length; i++)
+ val = val.replace(new RegExp('\[_'+i+'\]', 'g'), arguments[i]);
+ return val.replace(/~\[/g, '[').replace(/~\]/g, ']');
};
diff --git a/data/js/misc.js b/data/js/misc.js
index ef18fe90..cf29bf26 100644
--- a/data/js/misc.js
+++ b/data/js/misc.js
@@ -252,7 +252,7 @@ if(byId('lang_select')) {
var ln = VARS.l10n_lang[i];
var icon = tag('acronym', {'class':'icons lang '+ln[0]}, ' ');
lst.appendChild(tag('li', {'class':'lang_selector'}, curlang == ln[0]
- ? tag('i', icon, mt('_lang_'+ln[0]))
+ ? tag('i', icon, ln[1])
: tag('a', {href:'/setlang?lang='+ln[0]+';ref='+encodeURIComponent(location.pathname+location.search)}, icon, ln[1])
));
}
diff --git a/data/js/vnreldropdown.js b/data/js/vnreldropdown.js
index 8d7a9fef..e7cb267a 100644
--- a/data/js/vnreldropdown.js
+++ b/data/js/vnreldropdown.js
@@ -1,4 +1,4 @@
-function rlDropDown(lnk) {
+function dropdown(lnk) {
var relid = lnk.id.substr(6);
var st = getText(lnk);
if(st == mt('_js_loading'))
@@ -6,32 +6,31 @@ function rlDropDown(lnk) {
var o = tag('ul', null);
for(var i=0; i<VARS.rlist_status.length; i++) {
- var val = VARS.rlist_status[i] == 0 ? mt('_unknown') : mt('_rlist_status_'+VARS.rlist_status[i]); // l10n /_rlist_status_\d+/
- if(st == val)
- o.appendChild(tag('li', tag('i', val)));
- else
- o.appendChild(tag('li', tag('a', {href:'#', rl_rid:relid, rl_act:VARS.rlist_status[i], onclick:rlMod}, val)));
+ var val = VARS.rlist_status[i];
+ o.appendChild(tag('li', st == val
+ ? tag('i', val)
+ : tag('a', {href:'#', rl_rid:relid, rl_act:i, onclick:change}, val)));
}
if(st != '--')
- o.appendChild(tag('li', tag('a', {href:'#', rl_rid:relid, rl_act:-1, onclick:rlMod}, mt('_vnpage_uopt_reldel'))));
+ o.appendChild(tag('li', tag('a', {href:'#', rl_rid:relid, rl_act:-1, onclick:change}, mt('_vnpage_uopt_reldel'))));
return tag('div', o);
}
-function rlMod() {
+function change() {
var lnk = byId('rlsel_'+this.rl_rid);
var code = getText(byId('vnrlist_code'));
var act = this.rl_act;
ddHide();
setContent(lnk, tag('b', {'class': 'grayedout'}, mt('_js_loading')));
ajax('/xml/rlist.xml?formcode='+code+';id='+this.rl_rid+';e='+act, function(hr) {
- setText(lnk, act == -1 ? '--' : act == 0 ? mt('_unknown') : mt('_rlist_status_'+act));
+ setText(lnk, act == -1 ? '--' : VARS.rlist_status[act]);
});
return false;
}
if(byId('vnrlist_code')) {
var l = byClass('a', 'vnrlsel');
- for(var i=0;i<l.length;i++)
- ddInit(l[i], 'left', rlDropDown);
+ for(var i=0; i<l.length; i++)
+ ddInit(l[i], 'left', dropdown);
}
diff --git a/util/jsgen.pl b/util/jsgen.pl
index e2f8af87..784c80c0 100755
--- a/util/jsgen.pl
+++ b/util/jsgen.pl
@@ -37,6 +37,40 @@ sub l10n_load {
}
+# Remove formatting codes from L10N strings that the Javascript mt() does not support.
+# [quant,_n,x,..] -> x
+# [index,_n,x,..] -> x
+# [_n] is supported by Javascript mt(). It is left alone if no arguments are
+# given, otherwise it is replaced. All other codes result in an error.
+sub l10nstr {
+ my($lang, $key, @args) = @_;
+ local $_ = $lang{$lang}{$key} || $lang{'en'}{$key} || '';
+
+ # Simplify parsing
+ s/~\[/JSGEN_QBEGIN/g;
+ s/~]/JSGEN_QENDBR/g;
+ s/~,/JSGEN_QCOMMA/g;
+
+ # Replace quant/index
+ s/\[(?:quant|index),_[0-9]+,([^,\]]*)[^\]]*\]/$1/g;
+
+ # Replace [_n]
+ for my $i (0..$#args) {
+ my $v = $i+1;
+ s/\[_$v\]/$args[$i]/g;
+ }
+
+ # Check for unhandled codes
+ die "Unsupported formatting code in $lang:$key\n" if /\[[^_]/;
+
+ # Convert back
+ s/JSGEN_QBEGIN/~[/g;
+ s/JSGEN_QENDBR/~]/g;
+ s/JSGEN_QCOMMA/,/g; # No need to escape, at this point there are no codes with arguments
+ $_;
+}
+
+
sub l10n {
my($lang, $js) = @_;
@@ -44,14 +78,15 @@ sub l10n {
my @keys;
$js =~ s{(?:mt\('([a-z0-9_]+)'([,\)])|l10n /([^/]+)/)}#
my($k, $s, $q) = ($1, $2, $3);
- my $v = $k ? $lang{$lang}{$k} || $lang{'en'}{$k} : '';
- if($q) { $q ne '<perl regex>' && push @keys, qr/$q/; '' }
- elsif($s eq ')' && $v && $v !~ /[\~\[\]]/) {
+ my $v = $k && l10nstr($lang, $k);
+ if($q) {
+ $q ne '<perl regex>' && push @keys, qr/$q/; ''
+ } elsif($s eq ')' && $v && $v !~ /[\~\[\]]/) {
$v =~ s/"/\\"/g;
$v =~ s/\n/\\n/g;
qq{"$v"}
} else {
- push @keys, quotemeta($k);
+ push @keys, '^'.quotemeta($k).'$';
"mt('$k'$s"
}
#eg;
@@ -59,11 +94,7 @@ sub l10n {
my %keys;
for my $key (sort keys %{$lang{$lang}}) {
next if !grep $key =~ /$_/, @keys;
- my $val = $lang{$lang}{$key} || $lang{'en'}{$key};
- $val =~ s/"/\\"/g;
- $val =~ s/\n/\\n/g;
- $val =~ s/\[index,.+$// if $key =~ /^_vnlength_/; # special casing the VN lengths, since the JS mt() doesn't handle [index]
- $keys{$key} = $val;
+ $keys{$key} = l10nstr($lang, $key);
}
(\%keys, $js);
}
@@ -78,11 +109,11 @@ sub resolutions {
for my $i (0..$#{$S{resolutions}}) {
my $r = $S{resolutions}[$i];
if($cat ne $r->[1]) {
- push @r, [$r->[1] =~ /^_/ ? $lang{$ln}{$r->[1]}||$lang{'en'}{$r->[1]} : $r->[1]];
+ push @r, [$r->[1] =~ /^_/ ? l10nstr($ln, $r->[1]) : $r->[1]];
$cat = $r->[1];
$push = $r[$#r];
}
- my $n = $r->[0] =~ /^_/ ? $lang{$ln}{$r->[0]}||$lang{'en'}{$r->[0]} : $r->[0];
+ my $n = $r->[0] =~ /^_/ ? l10nstr($ln, $r->[0]) : $r->[0];
push @$push, [$i, $n];
}
\@r
@@ -92,12 +123,12 @@ sub resolutions {
sub vars {
my($lang, $l10n) = @_;
my %vars = (
- rlist_status => $S{rlist_status},
+ rlist_status => [ map l10nstr($lang, $_?"_rlist_status_$_":'_unknown'), @{$S{rlist_status}} ],
cookie_prefix => $O{cookie_prefix},
- age_ratings => $S{age_ratings},
- languages => $S{languages},
- platforms => $S{platforms},
- char_roles => $S{char_roles},
+ age_ratings => [ map [ $_, l10nstr($lang, $_ == -1 ? ('_unknown') : $_ == 0 ? ('_minage_all') : ('_minage_age', $_)) ], @{$S{age_ratings}} ],
+ languages => [ map [ $_, l10nstr($lang, "_lang_$_") ], @{$S{languages}} ],
+ platforms => [ map [ $_, l10nstr($lang, "_plat_$_") ], @{$S{platforms}} ],
+ char_roles => [ map [ $_, l10nstr($lang, "_charrole_$_") ], @{$S{char_roles}} ],
media => [sort keys %{$S{media}}],
release_types => $S{release_types},
animated => $S{animated},
@@ -105,10 +136,9 @@ sub vars {
vn_lengths => $S{vn_lengths},
blood_types => $S{blood_types},
genders => $S{genders},
- char_roles => $S{char_roles},
staff_roles => $S{staff_roles},
resolutions => scalar resolutions($lang),
- l10n_lang => [ map [ $_, $lang{$_}{"_lang_$_"}||$lang{en}{"_lang_$_"} ], VNDB::L10N::languages() ],
+ l10n_lang => [ map [ $_, l10nstr($_, "_lang_$_") ], VNDB::L10N::languages() ],
l10n_str => $l10n,
);
JSON::XS->new->encode(\%vars);