summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog1
-rw-r--r--data/script.js32
-rwxr-xr-xutil/jsgen.pl90
3 files changed, 71 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index 3774e5b7..b5033e15 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,7 @@
- Removed XML sitemap
- Added image dimensions to screenshot thumbail <img> tags
- Prefix all cookies with a configurable cookie_prefix
+ - Automatically read L10N keys from script.js
- Bugfix: only redirect VN search to VN page if page=1
- Bugfix: remove duplicate votes when merging tags (fixes a 500)
- Bugfix: Multi::Anime: don't crash when anidb returns an invalid or empty year
diff --git a/data/script.js b/data/script.js
index 3e2b479f..e3a1b553 100644
--- a/data/script.js
+++ b/data/script.js
@@ -14,6 +14,25 @@
* tvs -> VN page tag spoilers
* vnr -> VN relation editor
*/
+
+/* Internationalization note:
+ * The translation keys to be inserted in the header of this file are parsed
+ * from the source code. So when using mt(), make sure it is in the following
+ * format:
+ * mt('<exact translation key>',<more arguments>
+ * or
+ * mt('<exact translation key>')
+ * The single quotes and (lack of) spaces are significant!
+ *
+ * To use non-exact translation keys as argument to mt(), make sure to
+ * indicate which keys should be inserted in the header by adding a comment
+ * containing the following format:
+ * l10n /<perl regex>/
+ * any keys matching that regex will be included.
+ *
+ * The "_lang_*" keys for all languages for which we have a translation are
+ * already included automatically.
+ */
var expanded_icon = '▾';
var collapsed_icon = '▸';
@@ -365,14 +384,14 @@ function rlDropDown(lnk) {
var rs = tag('ul', tag('li', tag('b', mt('_vnpage_uopt_relrstat'))));
var vs = tag('ul', tag('li', tag('b', mt('_vnpage_uopt_relvstat'))));
for(var i=0; i<rlst_rstat.length; i++) {
- var val = mt('_rlst_rstat_'+rlst_rstat[i]);
+ var val = mt('_rlst_rstat_'+rlst_rstat[i]); // l10n /_rlst_rstat_\d+/
if(st[0] && st[0].indexOf(val) >= 0)
rs.appendChild(tag('li', tag('i', val)));
else
rs.appendChild(tag('li', tag('a', {href:'#', rl_rid:relid, rl_act:'r'+rlst_rstat[i], onclick:rlMod}, val)));
}
for(var i=0; i<rlst_vstat.length; i++) {
- var val = mt('_rlst_vstat_'+rlst_vstat[i]);
+ var val = mt('_rlst_vstat_'+rlst_vstat[i]); // l10n /_rlst_vstat_\d+/
if(st[1] && st[1].indexOf(val) >= 0)
vs.appendChild(tag('li', tag('i', val)));
else
@@ -1039,7 +1058,7 @@ function scrAdd(id, nsfw, rel) {
var tr = tag('tr', { id:'scr_tr_'+id, scr_id: id, scr_status: id?2:1, scr_rel: rel, scr_nsfw: nsfw},
tag('td', { 'class': 'thumb'}, mt('_js_loading')),
tag('td',
- tag('b', mt(id ? '_vnedit_scr_fetching' : '_vnedit_scr_uploading')),
+ tag('b', id ? mt('_vnedit_scr_fetching') : mt('_vnedit_scr_uploading')),
tag('br', null),
id ? null : mt('_vnedit_scr_upl_msg'),
tag('br', null),
@@ -1188,7 +1207,8 @@ function scrUploadComplete() {
tr.scr_id = -10;
}
if(tr.scr_id < 0) {
- alert(mt(tr.scr_id == -10 ? '_vnedit_scr_oops' : tr.scr_id == -1 ? '_vnedit_scr_errformat' : '_vnedit_scr_errempty'));
+ alert(tr.scr_id == -10 ? mt('_vnedit_scr_oops') :
+ tr.scr_id == -1 ? mt('_vnedit_scr_errformat') : mt('_vnedit_scr_errempty'));
scrDel(tr);
} else {
tr.id = 'scr_tr_'+tr.scr_id;
@@ -1231,7 +1251,7 @@ var tglSpoilers = [];
function tglLoad() {
for(var i=0; i<=3; i++)
- tglSpoilers[i] = mt('_tagv_spoil'+i);
+ tglSpoilers[i] = mt('_tagv_spoil'+i); // l10n /_tagv_spoil\d+/
// tag dropdown search
dsInit(byId('tagmod_tag'), '/xml/tags.xml?q=', function(item, tr) {
@@ -1871,7 +1891,7 @@ if(byId('expandlist')) {
var lnk = byId('expandlist');
setexpand = function() {
var exp = getCookie('histexpand') == 1;
- setText(lnk, mt(exp ? '_js_collapse' : '_js_expand'));
+ setText(lnk, exp ? mt('_js_collapse') : mt('_js_expand'));
var tbl = lnk;
while(tbl.nodeName.toLowerCase() != 'table')
tbl = tbl.parentNode;
diff --git a/util/jsgen.pl b/util/jsgen.pl
index 2235d289..27cbc6da 100755
--- a/util/jsgen.pl
+++ b/util/jsgen.pl
@@ -22,75 +22,73 @@ use LangFile;
use VNDB::L10N;
-my $jskeys_lang = join '|', VNDB::L10N::languages();
-my $jskeys = qr{^(?:
- _lang_(?:$jskeys_lang)|
- _js_.+|
- _menu_emptysearch|
- _vnpage_uopt_(?:10?vote|rel.+)|
- _rlst_[vr]stat_.+|
- _vnedit_rel_(?:isa|of|addbut|del|none|findformat|novn|double)|
- _redit_form_med_.+|
- _vnedit_scr_.+|
- _tagv_(?:add|spoil\d|notfound|nometa|double)|
- _redit_form_vn_(?:addbut|remove|none|vnformat|notfound|double)|
- _redit_form_prod_(?:addbut|remove|none|pformat|notfound|double)|
- _pedit_rel_(?:addbut|del|none|findformat|notfound|double)
- )$}x;
-
sub l10n {
- # Using JSON::XS or something may be shorter and less error prone,
- # although I would have less power over the output (mostly the quoting of the keys)
+ # parse the .js code to find the l10n keys to use
+ my $js = shift;
+ my @keys;
+ push @keys, $1 ? quotemeta($1) : qr/$2/ while($js =~ m{(?:mt\('([a-z0-9_]+)'[,\)]|l10n /([^/]+)/)}g);
+ # also add the _lang_* for all languages for which we have a translation
+ my $jskeys_lang = join '|', VNDB::L10N::languages();
+ push @keys, qr/_lang_(?:$jskeys_lang)/;
+ # fetch the corresponding text from lang.txt
+ my %lang; # key1 => { lang1 => .., lang2 => .. }, key2 => { .. }
my $lang = LangFile->new(read => "$ROOT/data/lang.txt");
- my @r;
- push @r, 'L10N_STR = {';
- my $cur; # undef = none/excluded, 1 = awaiting first TL line, 2 = after first TL line
- my %lang;
+ my $cur; # 0 = none/excluded, 1 = TL lines
+ my $key;
while((my $l = $lang->read())) {
my $type = shift @$l;
if($type eq 'key') {
- my $key = shift @$l;
- push @r, ' }' if $cur;
- $cur = $key =~ $jskeys ? 1 : undef;
- if($cur) {
- $r[$#r] .= ',' if $r[$#r] =~ /}$/;
- # let's assume key names don't trigger a reserved word in JS
- $key = qq{"$key"} if $key !~ /^[a-z_][a-z0-9_]*$/i;
- push @r, qq| $key: {|;
- }
+ my $k = shift @$l;
+ $cur = grep $k =~ /$_/, @keys;
+ $key = $k;
}
- $lang{$l->[0]} = 1 if $type eq 'tl';
if($type eq 'tl' && $cur) {
my($lang, $sync, $val) = @$l;
next if !$val;
+ $lang{$key}{$lang} = $val;
+ }
+ }
+
+ # generate JS code
+ my $r = "L10N_STR = {\n";
+ my $first = 1;
+ for my $key (sort keys %lang) {
+ $r .= ",\n" if !$first;
+ $first = 0;
+ # let's assume all L10N keys are valid JS variable names
+ $r .= sprintf qq| "%s": {\n|, $key;
+ my $firstk = 1;
+ for (sort keys %{$lang{$key}}) {
+ $r .= ",\n" if !$firstk;
+ $firstk = 0;
+ my $lang = $_;
+ $lang = qq{"$lang"} if $lang =~ /^(?:as|do|if|in|is)$/; # reserved two-char words
+ my $val = $lang{$key}{$_};
$val =~ s/"/\\"/g;
$val =~ s/\n/\\n/g;
- $r[$#r] .= ',' if $cur == 2;
- $lang = qq{"$l->[0]"} if $lang =~ /^(?:as|do|if|in|is)$/; # reserved two-char words
- push @r, qq| $lang: "$val"|;
- $cur = 2;
+ $r .= sprintf qq| %s: "%s"|, $lang, $val;
}
+ $r .= "\n }";
}
- push @r, ' }' if $cur;
- push @r, '};';
- push @r, 'L10N_LANG = [ '.join(', ', map qq{"$_"}, VNDB::L10N::languages()).' ];';
- return join "\n", @r;
+ $r .= "\n};\n";
+ $r .= 'L10N_LANG = [ '.join(', ', map qq{"$_"}, VNDB::L10N::languages()).' ];';
+ return "$r\n";
}
sub jsgen {
# JavaScript::Minifier::XS doesn't correctly handle perl's unicode,
# so just do everything in raw bytes instead.
- my $js = encode_utf8(l10n()) . "\n";
- $js .= sprintf "rlst_rstat = [ %s ];\n", join ', ', map qq{"$_"}, @{$S{rlst_rstat}};
- $js .= sprintf "rlst_vstat = [ %s ];\n", join ', ', map qq{"$_"}, @{$S{rlst_vstat}};
- $js .= sprintf "cookie_prefix = '%s';\n", $S{cookie_prefix};
open my $JS, '<', "$ROOT/data/script.js" or die $!;
- $js .= join '', <$JS>;
+ my $js .= join '', <$JS>;
close $JS;
+ my $head = encode_utf8(l10n($js)) . "\n";
+ $head .= sprintf "rlst_rstat = [ %s ];\n", join ', ', map qq{"$_"}, @{$S{rlst_rstat}};
+ $head .= sprintf "rlst_vstat = [ %s ];\n", join ', ', map qq{"$_"}, @{$S{rlst_vstat}};
+ $head .= sprintf "cookie_prefix = '%s';\n", $S{cookie_prefix};
open my $NEWJS, '>', "$ROOT/static/f/script.js" or die $!;
- print $NEWJS $JavaScript::Minifier::XS::VERSION ? JavaScript::Minifier::XS::minify($js) : $js;
+ print $NEWJS $JavaScript::Minifier::XS::VERSION ? JavaScript::Minifier::XS::minify($head.$js) : $head.$js;
close $NEWJS;
}