diff options
author | Yorhel <git@yorhel.nl> | 2015-08-15 13:46:15 +0200 |
---|---|---|
committer | Yorhel <git@yorhel.nl> | 2015-08-15 13:46:15 +0200 |
commit | 295ccf2ef58898b1cbee32a137ae859d67237a3a (patch) | |
tree | 2f7fd478ad13da179830e7b63dc35cd29e401920 | |
parent | 8c1c8311f5910d8bf62eee449c20d87b62412239 (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.pl | 2 | ||||
-rw-r--r-- | data/js/charvns.js | 4 | ||||
-rw-r--r-- | data/js/filter.js | 31 | ||||
-rw-r--r-- | data/js/lib.js | 22 | ||||
-rw-r--r-- | data/js/misc.js | 2 | ||||
-rw-r--r-- | data/js/vnreldropdown.js | 21 | ||||
-rwxr-xr-x | util/jsgen.pl | 66 |
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); |