]> git.sesse.net Git - wloh/commitdiff
Support translation of templates via po4a. Add an English translation as an example.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 10 Jun 2012 01:24:22 +0000 (03:24 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 10 Jun 2012 09:27:50 +0000 (11:27 +0200)
include/common.pm
po/en.po [new file with mode: 0644]
po/wloh.pot [new file with mode: 0644]
po4a.config [new file with mode: 0644]
templates/index.en.xml [new file with mode: 0644]
templates/rating.en.xml [new file with mode: 0644]
templates/scenario-not-found.en.xml [new file with mode: 0644]
templates/scenario.en.xml [new file with mode: 0644]
www/index.pl
www/rating.pl

index 6ad6ae403e04d70459994625a98e8db2ab100719..7ffaeeee0e8fc7ab4cae055559e7621a81ef3675 100644 (file)
@@ -35,6 +35,12 @@ sub get_locale {
        return $1;
 }
 
+sub set_locale {
+       my $locale = shift;
+       $locale =~ s/-/_/;
+       POSIX::setlocale(&POSIX::LC_ALL, $locale . '.UTF-8');
+}
+
 sub get_auxillary_parameters {
        my ($dbh, $locale) = @_;
 
@@ -106,10 +112,26 @@ sub print_navbar {
        print "</p>\n";
 }
 
+# mapping from locale to translation to use (if not found, "en" is used)
+my %translation_mapping = (
+       'nb-NO' => 'no',
+       'nn-NO' => 'no',
+       'da-DK' => 'no',
+       'sv-SE' => 'no',
+       'nl-NL' => 'en',
+);
+
 sub process_template {
-       my ($filename, $parms) = @_;
+       my ($filename, $locale, $parms) = @_;
 
-       my $doc = XML::Template::process_file('../templates/' . $filename, $parms);
+       my $translation = $translation_mapping{$locale} // 'en';
+       my $doc;
+       if (-r "../templates/$filename.$translation.xml") {
+               $parms->{'html/xml:lang'} = $translation;
+               $doc = XML::Template::process_file("../templates/$filename.$translation.xml", $parms);
+       } else {
+               $doc = XML::Template::process_file("../templates/$filename.xml", $parms);
+       }
        print $doc->toString;
 }
 
diff --git a/po/en.po b/po/en.po
new file mode 100644 (file)
index 0000000..2c84281
--- /dev/null
+++ b/po/en.po
@@ -0,0 +1,313 @@
+# SOME DESCRIPTIVE TITLE
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2012-06-10 03:20+0300\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: en\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. type: Content of: <html><head><title>
+#: templates/index.xml:7 templates/index.xml:31 templates/scenario.xml:7
+#: templates/scenario-not-found.xml:7
+#, no-wrap
+msgid "WLoH-plasseringsannsynlighetsberegning"
+msgstr "WLoH ranking probability calculation"
+
+#. type: Content of: <html><body><p><t:languages><t:separator>
+#: templates/index.xml:25 templates/rating.xml:13
+#, no-wrap
+msgid "::"
+msgstr "::"
+
+#. type: Content of: <html><body><p><em>
+#: templates/index.xml:33 templates/rating.xml:21
+#, no-wrap
+msgid ""
+"Dette er et hobbyprosjekt fra tredjepart, og ikke en offisiell del av\n"
+"      "
+msgstr "This is a hobby project from a third party, and not an official part of "
+
+#. type: Content of: <html><body><p><em><a>
+#: templates/index.xml:34 templates/rating.xml:22
+#, no-wrap
+msgid "Wordfeud League of Honour"
+msgstr "Wordfeud League of Honour"
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:34 templates/index.xml:79 templates/index.xml:121
+#: templates/index.xml:122 templates/rating.xml:22 templates/rating.xml:28
+#: templates/rating.xml:41 templates/rating.xml:95
+#, no-wrap
+msgid "."
+msgstr "."
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:36
+#, no-wrap
+msgid ""
+"Beregningen tar ikke hensyn til ujevn spillestyrke, ting som er sagt i forumet e.l.;\n"
+"      den antar at samtlige uspilte kamper trekkes fra en normalfordeling med standardavvik\n"
+"      "
+msgstr "The calculation does not take into account uneven playing strength, information from the forum etc.; it assumes that any unplayed games are drawn from a Gaussian distribution with standard deviation "
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:38
+#, no-wrap
+msgid ""
+" poeng. Sannsynlighetene kan summere til andre tall enn 100% pga. avrunding.\n"
+"      Tallene vil variere litt fra gang til gang fordi utregningen skjer ved randomisering.\n"
+"      For scenarioeksempel, klikk i en rute."
+msgstr " points. The probabilities might not sum to 100%, due to roundoff errors. The numbers will vary a bit between runs, since the calculation is stochastic. For scenario example, click in a cell."
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:42
+#, no-wrap
+msgid "Spillerne er sortert etter nick."
+msgstr "The players are sorted by nickname."
+
+#. type: Content of: <html><body><form><p>
+#: templates/index.xml:45
+#, no-wrap
+msgid ""
+"Divisjon:\n"
+"        "
+msgstr "Division:"
+
+#. type: Content of: <html><body><form><p>
+#: templates/index.xml:49
+#, no-wrap
+msgid ""
+"        Avdeling:\n"
+"        "
+msgstr "Subdivision:"
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:78
+#, no-wrap
+msgid ""
+"Under er en variant som tar relativ spillestyrke med i beregningen;\n"
+"      se "
+msgstr "Below is a variant that takes relative playing strength into account; see "
+
+#. type: Content of: <html><body><p><a>
+#: templates/index.xml:79
+#, no-wrap
+msgid "ratingsiden"
+msgstr "the ratings page"
+
+#. type: Content of: <html><body><t:cov-table><p>
+#: templates/index.xml:103
+#, no-wrap
+msgid "Kovarianstabell:"
+msgstr "Covariance matrix:"
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:121
+#, no-wrap
+msgid "Gjennomsnittlig rating i denne avdelingen er "
+msgstr "Average rating in this subdivision is "
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:122 templates/rating.xml:95
+#, no-wrap
+msgid "Databasen ble sist synkronisert "
+msgstr "The database was last synchronized "
+
+#. type: Content of: <html><body><h1>
+#: templates/rating.xml:7 templates/rating.xml:19
+#, no-wrap
+msgid "WLoH-rating"
+msgstr "WLoH rating"
+
+#. type: Content of: <html><body><p>
+#: templates/rating.xml:24
+#, no-wrap
+msgid ""
+"Ratingen er dog basert på spilledata fra WLoH (takk til Lobotommy\n"
+"      for tilgang!), og oppdateres\n"
+"      hver hele time. Den er fullstendig uoffisiell, og har ingen innflytelse\n"
+"      på WLoH, men brukes for å estimere vinnersannsynligheter i\n"
+"      "
+msgstr "Even so, the rating is based on play data from WLoH (thanks to Lobotommy for access!), and is updated every hour. It is completely unofficial and has no bearing on WLoH, but is used to estimate win probabilities in "
+
+#. type: Content of: <html><body><p><a>
+#: templates/rating.xml:28
+#, no-wrap
+msgid "sannsynlighetsberegningen"
+msgstr "the probability calculation"
+
+#. type: Content of: <html><body><p>
+#: templates/rating.xml:30
+#, no-wrap
+msgid ""
+"Modellen kan endre seg når som helst når jeg føler for det :-)\n"
+"      Ikke ta ratingen alt for alvorlig, selv om den er basert på\n"
+"      relativt fornuftige matematiske modeller. Husk at all statistikk\n"
+"      sier mer om fortiden enn om framtiden."
+msgstr "The model can change at any time I feel like it :-) Do not take the rating too seriously, even though it is based on relatively reasonable mathematical models. Remember that all statistics say more about the past than about the future."
+
+#. type: Content of: <html><body><h2>
+#: templates/rating.xml:35
+#, no-wrap
+msgid "Modellparametre"
+msgstr "Model parameters"
+
+#. type: Content of: <html><body><p>
+#: templates/rating.xml:37
+#, no-wrap
+msgid ""
+"For de som vet litt om slikt. Det finnes også en lengre, mer detaljert\n"
+"      "
+msgstr "For those so inclined. There is also a longer, more detailed "
+
+#. type: Content of: <html><body><p><a>
+#: templates/rating.xml:38
+#, no-wrap
+msgid "forklaring"
+msgstr "explanation"
+
+#. type: Content of: <html><body><p>
+#: templates/rating.xml:38
+#, no-wrap
+msgid " beregnet på ikke-matematikere."
+msgstr " intended for non-mathematicians."
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:41
+#, no-wrap
+msgid "MLE-basert modell med én skalar (styrke) per spiller og to globale skalarer (begge standardavvik, se under), løst med syklisk MM (minorization-maximization). Antall iterasjoner før konvergens: "
+msgstr "MLE-based model with one scalar (strength) per player and to global scalars (both standard deviations; see below), solved using cyclic MM (minorization-maximization). Number of iterations to convergence: "
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:42
+#, no-wrap
+msgid "Rimelighetfunksjon, prior: Normalfordeling med µ=500, σ="
+msgstr "Likelihood function, prior: Gaussian distribution with µ=500, σ="
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:42 templates/rating.xml:43
+#, no-wrap
+msgid " (est.)"
+msgstr " (est.)"
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:43
+#, no-wrap
+msgid "Rimelighetfunksjon, per kamp: Normalfordeling med µ=(score1 - score2), σ="
+msgstr "Likelihood function, for each match: Gaussian distribution with µ=(score1 - score2), σ="
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:44
+#, no-wrap
+msgid ""
+"Vekting: Inneværende sesong samt de tre siste vektes fullt ut\n"
+"\t(likt med prior). Deretter eksponentielt synkende vekting, med\n"
+"        halveringstid på tre sesonger. Spill som er registrert med\n"
+"        0-0, 150-0, 0-150 eller 150-150 ignoreres."
+msgstr "Weight: Current and previous three seasons are given full weight (equal to the prior). Older seasons are weighted exponentially less, with half-life of three seasons. Matches stored as 0-0, 150-0, 0-150 eller 150-150 are ignored."
+
+#. type: Content of: <html><body><h2>
+#: templates/rating.xml:50
+#, no-wrap
+msgid "Divisjonsoversikt"
+msgstr "List of divisions"
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:55
+#, no-wrap
+msgid "Div."
+msgstr "Div."
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:56
+#, no-wrap
+msgid "Snitt"
+msgstr "Average"
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:57 templates/rating.xml:80
+#, no-wrap
+msgid "Std.avvik"
+msgstr "Std.dev"
+
+#. type: Content of: <html><body><h2>
+#: templates/rating.xml:72
+#, no-wrap
+msgid "Rankingliste"
+msgstr "Ranking list"
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:78
+#, no-wrap
+msgid "Nick"
+msgstr "Nickname"
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:79
+#, no-wrap
+msgid "Rating"
+msgstr "Rating"
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:81
+#, no-wrap
+msgid "Sist sett"
+msgstr "Last seen"
+
+#. type: Content of: <html><body><p>
+#: templates/scenario.xml:11
+#, no-wrap
+msgid "Scenario der "
+msgstr "Scenario where "
+
+#. type: Content of: <html><body><p>
+#: templates/scenario.xml:11
+#, no-wrap
+msgid " ender på "
+msgstr " ends in "
+
+#. type: Content of: <html><body><p>
+#: templates/scenario.xml:11
+#, no-wrap
+msgid " plass:"
+msgstr " place:"
+
+#. type: Content of: <html><body><ul><li>
+#: templates/scenario.xml:13
+#, no-wrap
+msgid " – "
+msgstr " – "
+
+#. type: Content of: <html><body><ul><li>
+#: templates/scenario.xml:13
+#, no-wrap
+msgid ": "
+msgstr ": "
+
+#. type: Content of: <html><body><p>
+#: templates/scenario-not-found.xml:11
+#, no-wrap
+msgid "Fant ingen måte "
+msgstr "Couldn't find a situation where "
+
+#. type: Content of: <html><body><p>
+#: templates/scenario-not-found.xml:11
+#, no-wrap
+msgid " kan ende på "
+msgstr " ends up in "
+
+#. type: Content of: <html><body><p>
+#: templates/scenario-not-found.xml:11
+#, no-wrap
+msgid " plass på."
+msgstr " place."
diff --git a/po/wloh.pot b/po/wloh.pot
new file mode 100644 (file)
index 0000000..a386454
--- /dev/null
@@ -0,0 +1,318 @@
+# SOME DESCRIPTIVE TITLE
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2012-06-10 03:20+0300\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. type: Content of: <html><head><title>
+#: templates/index.xml:7 templates/index.xml:31 templates/scenario.xml:7 templates/scenario-not-found.xml:7
+#, no-wrap
+msgid "WLoH-plasseringsannsynlighetsberegning"
+msgstr ""
+
+#. type: Content of: <html><body><p><t:languages><t:separator>
+#: templates/index.xml:25 templates/rating.xml:13
+#, no-wrap
+msgid "::"
+msgstr ""
+
+#. type: Content of: <html><body><p><em>
+#: templates/index.xml:33 templates/rating.xml:21
+#, no-wrap
+msgid ""
+"Dette er et hobbyprosjekt fra tredjepart, og ikke en offisiell del av\n"
+"      "
+msgstr ""
+
+#. type: Content of: <html><body><p><em><a>
+#: templates/index.xml:34 templates/rating.xml:22
+#, no-wrap
+msgid "Wordfeud League of Honour"
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:34 templates/index.xml:79 templates/index.xml:121 templates/index.xml:122 templates/rating.xml:22 templates/rating.xml:28 templates/rating.xml:41 templates/rating.xml:95
+#, no-wrap
+msgid "."
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:36
+#, no-wrap
+msgid ""
+"Beregningen tar ikke hensyn til ujevn spillestyrke, ting som er sagt i "
+"forumet e.l.;\n"
+"      den antar at samtlige uspilte kamper trekkes fra en normalfordeling "
+"med standardavvik\n"
+"      "
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:38
+#, no-wrap
+msgid ""
+" poeng. Sannsynlighetene kan summere til andre tall enn 100% "
+"pga. avrunding.\n"
+"      Tallene vil variere litt fra gang til gang fordi utregningen skjer ved "
+"randomisering.\n"
+"      For scenarioeksempel, klikk i en rute."
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:42
+#, no-wrap
+msgid "Spillerne er sortert etter nick."
+msgstr ""
+
+#. type: Content of: <html><body><form><p>
+#: templates/index.xml:45
+#, no-wrap
+msgid ""
+"Divisjon:\n"
+"        "
+msgstr ""
+
+#. type: Content of: <html><body><form><p>
+#: templates/index.xml:49
+#, no-wrap
+msgid ""
+"        Avdeling:\n"
+"        "
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:78
+#, no-wrap
+msgid ""
+"Under er en variant som tar relativ spillestyrke med i beregningen;\n"
+"      se "
+msgstr ""
+
+#. type: Content of: <html><body><p><a>
+#: templates/index.xml:79
+#, no-wrap
+msgid "ratingsiden"
+msgstr ""
+
+#. type: Content of: <html><body><t:cov-table><p>
+#: templates/index.xml:103
+#, no-wrap
+msgid "Kovarianstabell:"
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:121
+#, no-wrap
+msgid "Gjennomsnittlig rating i denne avdelingen er "
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/index.xml:122 templates/rating.xml:95
+#, no-wrap
+msgid "Databasen ble sist synkronisert "
+msgstr ""
+
+#. type: Content of: <html><body><h1>
+#: templates/rating.xml:7 templates/rating.xml:19
+#, no-wrap
+msgid "WLoH-rating"
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/rating.xml:24
+#, no-wrap
+msgid ""
+"Ratingen er dog basert på spilledata fra WLoH (takk til Lobotommy\n"
+"      for tilgang!), og oppdateres\n"
+"      hver hele time. Den er fullstendig uoffisiell, og har ingen "
+"innflytelse\n"
+"      på WLoH, men brukes for å estimere vinnersannsynligheter i\n"
+"      "
+msgstr ""
+
+#. type: Content of: <html><body><p><a>
+#: templates/rating.xml:28
+#, no-wrap
+msgid "sannsynlighetsberegningen"
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/rating.xml:30
+#, no-wrap
+msgid ""
+"Modellen kan endre seg når som helst når jeg føler for det :-)\n"
+"      Ikke ta ratingen alt for alvorlig, selv om den er basert på\n"
+"      relativt fornuftige matematiske modeller. Husk at all statistikk\n"
+"      sier mer om fortiden enn om framtiden."
+msgstr ""
+
+#. type: Content of: <html><body><h2>
+#: templates/rating.xml:35
+#, no-wrap
+msgid "Modellparametre"
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/rating.xml:37
+#, no-wrap
+msgid ""
+"For de som vet litt om slikt. Det finnes også en lengre, mer detaljert\n"
+"      "
+msgstr ""
+
+#. type: Content of: <html><body><p><a>
+#: templates/rating.xml:38
+#, no-wrap
+msgid "forklaring"
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/rating.xml:38
+#, no-wrap
+msgid " beregnet på ikke-matematikere."
+msgstr ""
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:41
+#, no-wrap
+msgid ""
+"MLE-basert modell med én skalar (styrke) per spiller og to globale skalarer "
+"(begge standardavvik, se under), løst med syklisk MM "
+"(minorization-maximization). Antall iterasjoner før konvergens: "
+msgstr ""
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:42
+#, no-wrap
+msgid "Rimelighetfunksjon, prior: Normalfordeling med µ=500, σ="
+msgstr ""
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:42 templates/rating.xml:43
+#, no-wrap
+msgid " (est.)"
+msgstr ""
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:43
+#, no-wrap
+msgid "Rimelighetfunksjon, per kamp: Normalfordeling med µ=(score1 - score2), σ="
+msgstr ""
+
+#. type: Content of: <html><body><ul><li>
+#: templates/rating.xml:44
+#, no-wrap
+msgid ""
+"Vekting: Inneværende sesong samt de tre siste vektes fullt ut\n"
+"\t(likt med prior). Deretter eksponentielt synkende vekting, med\n"
+"        halveringstid på tre sesonger. Spill som er registrert med\n"
+"        0-0, 150-0, 0-150 eller 150-150 ignoreres."
+msgstr ""
+
+#. type: Content of: <html><body><h2>
+#: templates/rating.xml:50
+#, no-wrap
+msgid "Divisjonsoversikt"
+msgstr ""
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:55
+#, no-wrap
+msgid "Div."
+msgstr ""
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:56
+#, no-wrap
+msgid "Snitt"
+msgstr ""
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:57 templates/rating.xml:80
+#, no-wrap
+msgid "Std.avvik"
+msgstr ""
+
+#. type: Content of: <html><body><h2>
+#: templates/rating.xml:72
+#, no-wrap
+msgid "Rankingliste"
+msgstr ""
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:78
+#, no-wrap
+msgid "Nick"
+msgstr ""
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:79
+#, no-wrap
+msgid "Rating"
+msgstr ""
+
+#. type: Content of: <html><body><table><thead><tr><th>
+#: templates/rating.xml:81
+#, no-wrap
+msgid "Sist sett"
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/scenario.xml:11
+#, no-wrap
+msgid "Scenario der "
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/scenario.xml:11
+#, no-wrap
+msgid " ender på "
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/scenario.xml:11
+#, no-wrap
+msgid " plass:"
+msgstr ""
+
+#. type: Content of: <html><body><ul><li>
+#: templates/scenario.xml:13
+#, no-wrap
+msgid " – "
+msgstr ""
+
+#. type: Content of: <html><body><ul><li>
+#: templates/scenario.xml:13
+#, no-wrap
+msgid ": "
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/scenario-not-found.xml:11
+#, no-wrap
+msgid "Fant ingen måte "
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/scenario-not-found.xml:11
+#, no-wrap
+msgid " kan ende på "
+msgstr ""
+
+#. type: Content of: <html><body><p>
+#: templates/scenario-not-found.xml:11
+#, no-wrap
+msgid " plass på."
+msgstr ""
diff --git a/po4a.config b/po4a.config
new file mode 100644 (file)
index 0000000..65fa2c5
--- /dev/null
@@ -0,0 +1,5 @@
+[po_directory] po/
+[type:xml] templates/index.xml en:templates/index.en.xml
+[type:xml] templates/rating.xml en:templates/rating.en.xml
+[type:xml] templates/scenario.xml en:templates/scenario.en.xml
+[type:xml] templates/scenario-not-found.xml en:templates/scenario-not-found.en.xml
diff --git a/templates/index.en.xml b/templates/index.en.xml
new file mode 100644 (file)
index 0000000..90e9354
--- /dev/null
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE
+  html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="no" xmlns:t="http://template.sesse.net/">
+  <head>
+    <title>WLoH ranking probability calculation</title>
+    <link rel="stylesheet" href="style" type="text/css" />
+    <script type="text/javascript">
+<!--
+function showScenario(element_id, url) {
+    var obj = document.getElementById(element_id);
+    var parent = obj.parentElement;
+    parent.removeChild(obj);
+    obj = obj.cloneNode(false);
+    obj.data = url;
+    parent.appendChild(obj);
+}
+    //-->
+    
+    </script>
+  </head>
+  <body>
+    <p style="font-size: smaller;" t:id="navbar">
+      <t:languages>
+        <t:separator>::</t:separator>
+        <t:lang-with-link><a /></t:lang-with-link>
+        <t:lang-no-link />
+      </t:languages>
+    </p>
+
+    <h1>WLoH ranking probability calculation</h1>
+
+    <p><em>This is a hobby project from a third party, and not an official part of <a href="http://wordfeud.aasmul.net/">Wordfeud League of Honour</a>.</em></p>
+
+    <p>The calculation does not take into account uneven playing strength, information from the forum etc.; it assumes that any unplayed games are drawn from a Gaussian distribution with standard deviation <t:match-stddev /> points. The probabilities might not sum to 100%, due to roundoff errors. The numbers will vary a bit between runs, since the calculation is stochastic. For scenario example, click in a cell.</p>
+
+    <p>The players are sorted by nickname.</p>
+
+    <form method="get" t:id="division-selector">
+      <p>Division:<select name="divisjon" onchange="form.submit();" t:id="division">
+          <option />
+        </select>
+Subdivision:<select name="avdeling" onchange="form.submit();" t:id="subdivision">
+          <option />
+        </select>
+        <input type="submit" value="Vis" />
+      </p>
+    </form>
+
+    <table class="probmatrix" t:id="basic-probabilities">
+      <thead>
+        <tr>
+          <th></th>
+          <t:ranks>
+            <th />
+          </t:ranks>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <th><t:player /></th>
+          <t:player-ranks>
+            <td class="num"><t:link><a class="unmarkedlink" /></t:link><t:no-link /></td>
+          </t:player-ranks>
+        </tr>
+      </tbody>
+    </table>
+    
+    <p class="scenario"><object id="scenario1" data="" type="text/html"> </object></p>
+
+    <p style="clear: both; padding-top: 1em;">Below is a variant that takes relative playing strength into account; see <a href="rating">the ratings page</a>.</p>
+
+    <table class="probmatrix" t:id="adjusted-probabilities">
+      <thead>
+        <tr>
+          <th></th>
+          <t:ranks>
+            <th />
+          </t:ranks>
+        </tr>
+      </thead>
+      <tbody>
+        <tr>
+          <th><t:player /></th>
+          <t:player-ranks>
+            <td class="num"><t:link><a class="unmarkedlink" /></t:link><t:no-link /></td>
+          </t:player-ranks>
+        </tr>
+      </tbody>
+    </table>
+    
+    <p class="scenario"><object id="scenario2" data="" type="text/html"> </object></p>
+
+    <t:cov-table>
+      <p style="clear: both; padding-top: 1em;">Covariance matrix:</p>
+
+      <table>
+        <thead>
+          <tr>
+            <th />
+            <t:player-list><th /></t:player-list>
+          </tr>
+        </thead>
+        <tbody>
+          <tr>
+            <th t:id="player" />
+            <t:elements><td class="num" /></t:elements>
+          </tr>
+        </tbody>
+      </table>
+    </t:cov-table>
+
+    <p style="clear: both; padding-top: 1em;">Average rating in this subdivision is <strong t:id="average-rating" />.</p>
+    <p class="lastsync">The database was last synchronized <t:last-sync />.</p>
+  </body>
+</html>
diff --git a/templates/rating.en.xml b/templates/rating.en.xml
new file mode 100644 (file)
index 0000000..e570bea
--- /dev/null
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE
+  html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="no" xmlns:t="http://template.sesse.net/">
+  <head>
+    <title>WLoH rating</title>
+    <link rel="stylesheet" href="style" type="text/css" />
+  </head>
+  <body>
+    <p style="font-size: smaller;" t:id="navbar">
+      <t:languages>
+        <t:separator>::</t:separator>
+        <t:lang-with-link><a /></t:lang-with-link>
+        <t:lang-no-link />
+      </t:languages>
+    </p>
+
+    <h1>WLoH rating</h1>
+
+    <p><em>This is a hobby project from a third party, and not an official part of <a href="http://wordfeud.aasmul.net/">Wordfeud League of Honour</a>.</em></p>
+
+    <p>Even so, the rating is based on play data from WLoH (thanks to Lobotommy for access!), and is updated every hour. It is completely unofficial and has no bearing on WLoH, but is used to estimate win probabilities in <a href="index">the probability calculation</a>.</p>
+
+    <p>The model can change at any time I feel like it :-) Do not take the rating too seriously, even though it is based on relatively reasonable mathematical models. Remember that all statistics say more about the past than about the future.</p>
+
+    <h2>Model parameters</h2>
+
+    <p>For those so inclined. There is also a longer, more detailed <a href="ratings-explained">explanation</a> intended for non-mathematicians.</p>
+
+    <ul>
+      <li>MLE-based model with one scalar (strength) per player and to global scalars (both standard deviations; see below), solved using cyclic MM (minorization-maximization). Number of iterations to convergence: <t:iterations />.</li>
+      <li>Likelihood function, prior: Gaussian distribution with µ=500, σ=<t:rating-prior-stddev /> (est.)</li>
+      <li>Likelihood function, for each match: Gaussian distribution with µ=(score1 - score2), σ=<t:match-stddev /> (est.)</li>
+      <li>Weight: Current and previous three seasons are given full weight (equal to the prior). Older seasons are weighted exponentially less, with half-life of three seasons. Matches stored as 0-0, 150-0, 0-150 eller 150-150 are ignored.</li>
+    </ul>
+
+    <h2>List of divisions</h2>
+
+    <table>
+      <thead>
+        <tr>
+          <th>Div.</th>
+          <th>Average</th>
+          <th>Std.dev</th>
+        </tr>
+      </thead>
+      <tbody t:id="divisions">
+        <tr>
+          <th t:id="rank" />
+          <td class="num" t:id="average" />
+          <td class="num" t:id="stddev" />
+          <t:subdivisions>
+            <td class="num"><a t:id="divlink" /></td>
+          </t:subdivisions>
+        </tr>
+      </tbody>
+    </table>
+
+    <h2>Ranking list</h2>
+  
+    <table>
+      <thead>
+        <tr>
+          <th></th>
+          <th>Nickname</th>
+          <th>Rating</th>
+          <th>Std.dev</th>
+          <th>Last seen</th>
+        </tr>
+      </thead>
+      <tbody t:id="players">
+        <tr>
+          <th t:id="rank" />
+          <td><a t:id="user" /></td>
+          <td class="num" t:id="rating" />
+          <td class="num" t:id="stddev" />
+          <td><a t:id="divlink" /></td>
+        </tr>
+      </tbody>
+    </table>
+
+    <p class="lastsync">The database was last synchronized <t:last-sync />.</p>
+  </body>
+</html>
diff --git a/templates/scenario-not-found.en.xml b/templates/scenario-not-found.en.xml
new file mode 100644 (file)
index 0000000..7c52aa0
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE
+  html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="no" xmlns:t="http://template.sesse.net/">
+  <head>
+    <title>WLoH ranking probability calculation</title>
+    <link rel="stylesheet" href="style" type="text/css" />
+  </head>
+  <body>
+    <p>Couldn't find a situation where <strong t:id="nick" /> ends up in <strong t:id="rank" /> place.</p>
+  </body>
+</html>
diff --git a/templates/scenario.en.xml b/templates/scenario.en.xml
new file mode 100644 (file)
index 0000000..27aed09
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE
+  html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="no" xmlns:t="http://template.sesse.net/">
+  <head>
+    <title>WLoH ranking probability calculation</title>
+    <link rel="stylesheet" href="style" type="text/css" />
+  </head>
+  <body>
+    <p>Scenario where <strong t:id="nick" /> ends in <strong t:id="rank" /> place:</p>
+    <ul t:id="results">
+      <li><t:player-1 /> – <t:player-2 />: <t:result /></li>
+    </ul>
+  </body>
+</html>
index 2b7dcaf31c03080d745526cd1cbc843cfb5a8f4b..4fef4a7e4e319abe764e9edf78b844412cbb753d 100755 (executable)
@@ -138,9 +138,9 @@ sub get_covariance_matrix {
 }
 
 sub write_parms_to_file {
-       my ($aux_parms, $match_stddev, $used_ratings, $used_cov) = @_;
+       my ($locale, $aux_parms, $match_stddev, $used_ratings, $used_cov) = @_;
 
-       POSIX::setlocale(&POSIX::LC_ALL, 'nb_NO.UTF-8');
+       wloh_common::set_locale($locale);
 
        my @sorted_players = sort { $players{$a} cmp $players{$b} } keys %players;
 
@@ -175,7 +175,7 @@ sub write_parms_to_file {
        }
        close MCCALC;
 
-       POSIX::setlocale(&POSIX::LC_ALL, 'nb_NO.UTF-8');
+       wloh_common::set_locale($locale);
 
        return $tmpnam;
 }
@@ -183,7 +183,7 @@ sub write_parms_to_file {
 sub make_table {
        my ($locale, $aux_parms, $match_stddev, $lowest_division, $used_ratings, $used_cov, $division, $subdivision, $table_id) = @_;
 
-       my $tmpnam = write_parms_to_file($aux_parms, $match_stddev, $used_ratings, $used_cov);
+       my $tmpnam = write_parms_to_file($locale, $aux_parms, $match_stddev, $used_ratings, $used_cov);
        my %prob = ();
 
        open MCCALC, "$config::base_dir/mcwordfeud $trials < $tmpnam |"
@@ -352,7 +352,7 @@ get_players_and_ratings($dbh, $locale, $season, $division, $subdivision);
 my $cov = get_covariance_matrix($dbh, keys %players);
 
 if (defined($match_player) && defined($match_position)) {
-       my $tmpnam = write_parms_to_file($aux_parms, $match_stddev, \%ratings, $cov);
+       my $tmpnam = write_parms_to_file($locale, $aux_parms, $match_stddev, \%ratings, $cov);
 
        --$match_player;
        --$match_position;
@@ -377,20 +377,20 @@ if (defined($match_player) && defined($match_position)) {
 
        if (scalar @scenario == 0) {
                print CGI->header(-type=>'text/html; charset=utf-8', -expires=>'+5m');
-               wloh_common::process_template('scenario-not-found.xml', {
+               wloh_common::process_template('scenario-not-found', $locale, {
                        '#nick' => $player_name,
                        '#rank' => sprintf("%d.", $match_position + 1)
                });
        } else {
                print CGI->header(-type=>'text/html; charset=utf-8', -expires=>'+5m');
-               wloh_common::process_template('scenario.xml', {
+               wloh_common::process_template('scenario', $locale, {
                        '#nick' => $player_name,
                        '#rank' => sprintf("%d.", $match_position + 1),
                        '#results' => \@scenario
                });
        }
 } else {
-       POSIX::setlocale(&POSIX::LC_ALL, 'nb_NO.UTF-8');
+       wloh_common::set_locale($locale);
 
        my $max_division = $divisions[$#divisions];
        my $lowest_division = ($division == $max_division);
@@ -401,7 +401,7 @@ if (defined($match_player) && defined($match_position)) {
        my $avg_rating = find_avg_rating(\%ratings);
 
        print CGI->header(-type=>'text/html; charset=utf-8', -expires=>'+5m');
-       wloh_common::process_template('index.xml', {
+       wloh_common::process_template('index', $locale, {
                '#navbar' => wloh_common::get_navbar($cgi, $dbh, $locale),
                '#division-selector/action' => "/$locale/",
                '#division' => get_division_selector(\@divisions, $division),
index c69d5a7bf2004cfe1ae1fe3eb9b96ba056ffee60..dca62d89b527d0a305ded73cf00950282a5ea337 100755 (executable)
@@ -26,7 +26,7 @@ my $locale = wloh_common::get_locale($cgi);
 
 my $aux_parms = wloh_common::get_auxillary_parameters($dbh, $locale);
 
-POSIX::setlocale(&POSIX::LC_ALL, 'nb_NO.UTF-8');
+wloh_common::set_locale($locale);
 
 my $season = wloh_common::get_max_season($dbh, $locale);
 
@@ -98,7 +98,7 @@ while (my $ref = $q->fetchrow_hashref) {
 }
 
 print CGI->header(-type=>'text/html; charset=utf-8', -expires=>'+5m');
-wloh_common::process_template('rating.xml', {
+wloh_common::process_template('rating', $locale, {
        '#navbar' => wloh_common::get_navbar($cgi, $dbh, $locale),
        'iterations' => $aux_parms->{'num_iterations'},
        'rating-prior-stddev' => sprintf("%.1f", $aux_parms->{'rating_prior_stddev'}),