[gbrainy] Support for plural strings in games.xml
- From: Jordi Mas <jmas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gbrainy] Support for plural strings in games.xml
- Date: Sat, 17 Jul 2010 17:12:49 +0000 (UTC)
commit 2bb249c3ce3f7999dae1fd2d8c255fcab4713321
Author: Jordi Mas <jmas softcatala org>
Date: Sat Jul 17 19:14:03 2010 +0200
Support for plural strings in games.xml
Makefile.am | 1 +
configure.ac | 1 +
data/games.xml | 29 +++++---
po/POTFILES.in | 1 +
src/Core/Main/Xml/GameXml.cs | 57 +++++++++++---
src/Core/Main/Xml/GameXmlDefinition.cs | 22 +++++-
src/Core/Main/Xml/GameXmlFactory.cs | 68 ++++++++++++++---
tools/GameXmlGetStringTemplate.cs | 33 ++++++++
tools/GameXmlToGetString.cs | 128 ++++++++++++++++++++++++++++++++
tools/Makefile.am | 23 ++++++
10 files changed, 328 insertions(+), 35 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 151a302..886abef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,6 +2,7 @@ SUBDIRS = \
src \
tests \
data \
+ tools \
po \
help
diff --git a/configure.ac b/configure.ac
index c6810d7..b086178 100644
--- a/configure.ac
+++ b/configure.ac
@@ -182,6 +182,7 @@ src/Games/AssemblyInfo.cs
Makefile
po/Makefile.in
src/Makefile
+tools/Makefile
src/Core/Makefile
src/Games/Makefile
src/Clients/Classical/Makefile
diff --git a/data/games.xml b/data/games.xml
index 3e8b8f2..017210b 100644
--- a/data/games.xml
+++ b/data/games.xml
@@ -1,5 +1,4 @@
<!---
-
This is a collection of games definitions for gbrainy. This work is licensed under GPL 2.0 or higher license.
This is the same license that gbrainy package.
@@ -8,7 +7,6 @@
TODO:
* Mouse sensitive areas
- * Answer regular expression + patterns
-->
<games>
<game>
@@ -21,7 +19,8 @@
</variables>
<_rationale>Every hour rotates 360 degrees.</_rationale>
<svg file = "clock.svg" x = "0.25" y = "0.25" width = "0.5" height = "0.5"/>
- <_question>How many degrees rotates the minute hand of a clock in 2 hours [num] minutes?</_question>
+ <question>How many degrees rotates the minute hand of a clock in 2 hours [num] minute?</question>
+ <question plural ="[rslt]">How many degrees rotates the minute hand of a clock in 2 hours [num] minutes?</question>
<answer>[rslt]</answer>
</game>
@@ -58,7 +57,8 @@
int difference = 2 + random.Next (8);
int son = (father / 2) - difference;
</variables>
- <_question>John's is 46 years old. His son is [difference] years younger than half of John's age. How old is John's son?</_question>
+ <question>John's is 46 years old. His son is [difference] year younger than half of John's age. How old is John's son?</question>
+ <question plural ="[difference]">John's is 46 years old. His son is [difference] years younger than half of John's age. How old is John's son?</question>
<answer>[son]</answer>
</variant>
<variant>
@@ -70,9 +70,11 @@
int ago = years [idx];
int proportion = proportions [idx];
</variables>
- <_question>John's age is nowadays 2 times his son's age. [ago] years ago, John was [proportion] times older than his son. How old is John's son nowadays?</_question>
+ <question>John's age is nowadays 2 times his son's age. [ago] year ago, John was [proportion] times older than his son. How old is John's son nowadays?</question>
+ <question plural ="[ago]">John's age is nowadays 2 times his son's age. [ago] years ago, John was [proportion] times older than his son. How old is John's son nowadays?</question>
<answer>40</answer>
- <_rationale>[ago] years ago, John's age minus [ago] was equal to [proportion] times his son age minus [ago].</_rationale>
+ <rationale>[ago] year ago, John's age minus [ago] was equal to [proportion] times his son age minus [ago].</rationale>
+ <rationale plural ="[ago]">[ago] years ago, John's age minus [ago] was equal to [proportion] times his son age minus [ago].</rationale>
</variant>
</game>
@@ -86,7 +88,8 @@
int digits = 4 + random.Next (3);
int rslt = (int) Math.Pow (10, digits);
</variables>
- <_question>A file is protected by a password formed by a [digits] digit number (ranging from 0 to 9). How many different passwords can you have?</_question>
+ <question>A file is protected by a password formed by a [digits] digit number (ranging from 0 to 9). How many different passwords can you have?</question>
+ <question plural="[digits]">A file is protected by a password formed by a [digits] digits number (ranging from 0 to 9). How many different passwords can you have?</question>
<answer>[rslt]</answer>
<_rationale>Every digit has 10 possibilities. The total number of possibilities is 10 at the power of [digits].</_rationale>
</variant>
@@ -95,7 +98,8 @@
int digits = 2 + random.Next (2);
int rslt = (int) Math.Pow (8, digits);
</variables>
- <_question>A file is protected by a password formed by a [digits] digit octal number (ranging from 0 to 7). How many different passwords can you have?</_question>
+ <question>A file is protected by a password formed by a [digits] digit octal number (ranging from 0 to 7). How many different passwords can you have?</question>
+ <question plural="[digits]">A file is protected by a password formed by a [digits] digits octal number (ranging from 0 to 7). How many different passwords can you have?</question>
<answer>[rslt]</answer>
<_rationale>Every digit has 8 possibilities. The total number of possibilities is 8 at the power of [digits].</_rationale>
</variant>
@@ -111,7 +115,8 @@
int games = 5 + random.Next (5);
int rslt = (int) Math.Pow (2, games);
</variables>
- <_question>There are [games] tennis games played simultaneous. How many different forecast are possible?</_question>
+ <question>There are [games] tennis game played simultaneous. How many different forecast are possible?</question>
+ <question plural="[games]">There are [games] tennis games played simultaneous. How many different forecast are possible?</question>
<answer>[rslt]</answer>
<_rationale>Every game is an independent event with 2 possible results. The total number of possibilities is 2 at the power of [games].</_rationale>
</variant>
@@ -120,7 +125,8 @@
int players = 32 + (random.Next (16) * 2);
int rslt = players -1;
</variables>
- <_question>How many matches does it take to determine the winner of a tennis tournament that starts with [players] players?</_question>
+ <question>How many matches does it take to determine the winner of a tennis tournament that starts with [players] player?</question>
+ <question plural ="[players]">How many matches does it take to determine the winner of a tennis tournament that starts with [players] players?</question>
<_rationale>In every match you eliminate one player, you need the total number of games minus 1 to find out the winner.</_rationale>
<answer>[rslt]</answer>
</variant>
@@ -140,7 +146,8 @@
double rslt = money * (Math.Pow (1 + interest, years));
</variables>
- <_question>You have [money] monetary units in your bank account at 10% compound interest annually. How much money will you have at end of 2 years?</_question>
+ <question>You have [money] monetary unit in your bank account at 10% compound interest annually. How much money will you have at end of 2 years?</question>
+ <question plural = "[money]">You have [money] monetary units in your bank account at 10% compound interest annually. How much money will you have at end of 2 years?</question>
<answer>[rslt]</answer>
<_rationale>Compound interest is paid on the original amount and on the accumulated past interest.</_rationale>
</variant>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1ae3ccd..97a9092 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,3 +1,4 @@
+tools/GameXmlGetString.cs
data/games.xml
data/gbrainy.desktop.in
data/verbal_analogies.xml
diff --git a/src/Core/Main/Xml/GameXml.cs b/src/Core/Main/Xml/GameXml.cs
index 318455a..2ca4731 100644
--- a/src/Core/Main/Xml/GameXml.cs
+++ b/src/Core/Main/Xml/GameXml.cs
@@ -77,7 +77,7 @@ namespace gbrainy.Core.Main.Xml
if (String.IsNullOrEmpty (expression))
return base.AnswerCheckExpression;
-
+
return expression;
}
}
@@ -103,7 +103,7 @@ namespace gbrainy.Core.Main.Xml
}
public override string Name {
- get { return game.Name; }
+ get { return Catalog.GetString (game.Name); }
}
public override string Question {
@@ -130,9 +130,37 @@ namespace gbrainy.Core.Main.Xml
{
string variables;
bool variants;
+ LocalizableString localizable_question, localizable_rationale;
variants = game.Variants.Count > 0;
+ if (variants && game.Variants[current.Variant].Variables != null)
+ variables = game.Variants[current.Variant].Variables;
+ else
+ variables = game.Variables;
+
+ if (variants && game.Variants[current.Variant].Question != null)
+ localizable_question = game.Variants[current.Variant].Question;
+ else
+ localizable_question = game.Question;
+
+ if (variants && game.Variants[current.Variant].Rationale != null)
+ localizable_rationale = game.Variants[current.Variant].Rationale;
+ else
+ localizable_rationale = game.Rationale;
+
+ if (String.IsNullOrEmpty (variables) == false)
+ {
+ // Evaluate code
+ CodeEvaluation.EvaluateVariables (variables);
+
+ if (String.IsNullOrEmpty (localizable_question.Value) == false)
+ localizable_question.ValueComputed = Int32.Parse (CodeEvaluation.ReplaceVariables (localizable_question.Value));
+
+ if (localizable_rationale != null && String.IsNullOrEmpty (localizable_rationale.Value) == false)
+ localizable_rationale.ValueComputed = Int32.Parse (CodeEvaluation.ReplaceVariables (localizable_rationale.Value));
+ }
+
if (variants && game.Variants[current.Variant].Question != null)
question = CatalogGetString (game.Variants[current.Variant].Question);
else
@@ -153,18 +181,11 @@ namespace gbrainy.Core.Main.Xml
else
answer_value = game.AnswerShow;
- if (variants && game.Variants[current.Variant].Variables != null)
- variables = game.Variants[current.Variant].Variables;
- else
- variables = game.Variables;
-
if (String.IsNullOrEmpty (variables) == false)
{
- // Evaluate code
- CodeEvaluation.EvaluateVariables (variables);
question = CodeEvaluation.ReplaceVariables (question);
- answer = CodeEvaluation.ReplaceVariables (answer);
rationale = CodeEvaluation.ReplaceVariables (rationale);
+ answer = CodeEvaluation.ReplaceVariables (answer);
answer_value = CodeEvaluation.ReplaceVariables (answer_value);
}
@@ -213,7 +234,7 @@ namespace gbrainy.Core.Main.Xml
{
string text;
TextDrawingObject draw_string = draw_object as TextDrawingObject;
-
+
text = CatalogGetString (draw_string.Text);
text = CodeEvaluation.ReplaceVariables (text);
@@ -229,7 +250,7 @@ namespace gbrainy.Core.Main.Xml
gr.ShowPangoText (text);
gr.Stroke ();
}
- }
+ }
else if (draw_object is ImageDrawingObject)
{
ImageDrawingObject image = draw_object as ImageDrawingObject;
@@ -264,5 +285,17 @@ namespace gbrainy.Core.Main.Xml
return Catalog.GetString (str);
}
+
+ // Protect from calling with null + resolve plurals
+ string CatalogGetString (LocalizableString localizable)
+ {
+ if (localizable == null)
+ return string.Empty;
+
+ if (localizable.IsPlural () == false)
+ return CatalogGetString (localizable.String);
+
+ return Catalog.GetPluralString (localizable.String, localizable.PluralString, localizable.ValueComputed);
+ }
}
}
diff --git a/src/Core/Main/Xml/GameXmlDefinition.cs b/src/Core/Main/Xml/GameXmlDefinition.cs
index 0855ac4..a280eea 100644
--- a/src/Core/Main/Xml/GameXmlDefinition.cs
+++ b/src/Core/Main/Xml/GameXmlDefinition.cs
@@ -23,6 +23,24 @@ using System.Collections.Generic;
namespace gbrainy.Core.Main.Xml
{
+ public class LocalizableString
+ {
+ public string String { get; set; }
+ public string Value { get; set; }
+ public int ValueComputed { get; set; }
+ public string PluralString { get; set; }
+
+ public bool IsPlural ()
+ {
+ if (String.IsNullOrEmpty (String) == true ||
+ String.IsNullOrEmpty (PluralString) == true ||
+ String.IsNullOrEmpty (Value) == true)
+ return false;
+ else
+ return true;
+ }
+ }
+
public class DrawingObject
{
@@ -48,9 +66,9 @@ namespace gbrainy.Core.Main.Xml
public class GameXmlDefinitionVariant
{
- public string Question { get; set; }
+ public LocalizableString Question { get; set; }
public string Tip { get; set; }
- public string Rationale { get; set; }
+ public LocalizableString Rationale { get; set; }
public string Answer { get; set; }
public string Variables { get; set; }
public GameAnswerCheckAttributes CheckAttributes { get; set; }
diff --git a/src/Core/Main/Xml/GameXmlFactory.cs b/src/Core/Main/Xml/GameXmlFactory.cs
index 3cbfef5..d927df2 100644
--- a/src/Core/Main/Xml/GameXmlFactory.cs
+++ b/src/Core/Main/Xml/GameXmlFactory.cs
@@ -42,7 +42,7 @@ namespace gbrainy.Core.Main.Xml
public void Read (string file)
{
GameXmlDefinition game;
- string name, str;
+ string name, str, plural;
bool processing_variant = false;
int variant = 0;
@@ -57,7 +57,7 @@ namespace gbrainy.Core.Main.Xml
while (reader.Read ())
{
- name = reader.Name.ToLower ();
+ name = reader.Name.ToLower ();
switch (name) {
case "games":
break;
@@ -186,24 +186,72 @@ namespace gbrainy.Core.Main.Xml
break;
case "_question":
+ case "question":
if (reader.NodeType != XmlNodeType.Element)
break;
- if (processing_variant)
- game.Variants[variant].Question = reader.ReadElementString ();
- else
- game.Question = reader.ReadElementString ();
+ // Create object if needed
+ if (processing_variant) {
+ if (game.Variants[variant].Question == null)
+ game.Variants[variant].Question = new LocalizableString ();
+ }
+ else {
+ if (game.Question == null)
+ game.Question = new LocalizableString ();
+ }
+ plural = reader.GetAttribute ("plural");
+
+ if (String.IsNullOrEmpty (plural) == false) { // Plural
+ if (processing_variant) {
+ game.Variants[variant].Question.PluralString = reader.ReadElementString ();
+ game.Variants[variant].Question.Value = plural;
+ }
+ else {
+ game.Question.PluralString = reader.ReadElementString ();
+ game.Question.Value = plural;
+ }
+ }
+ else {
+ if (processing_variant)
+ game.Variants[variant].Question.String = reader.ReadElementString ();
+ else
+ game.Question.String = reader.ReadElementString ();
+ }
break;
+ case "rationale":
case "_rationale":
if (reader.NodeType != XmlNodeType.Element)
break;
- if (processing_variant)
- game.Variants[variant].Rationale = reader.ReadElementString ();
- else
- game.Rationale = reader.ReadElementString ();
+ // Create object if needed
+ if (processing_variant) {
+ if (game.Variants[variant].Rationale == null)
+ game.Variants[variant].Rationale = new LocalizableString ();
+ }
+ else {
+ if (game.Rationale == null)
+ game.Rationale = new LocalizableString ();
+ }
+ plural = reader.GetAttribute ("plural");
+
+ if (String.IsNullOrEmpty (plural) == false) { // Plural
+ if (processing_variant) {
+ game.Variants[variant].Rationale.PluralString = reader.ReadElementString ();
+ game.Variants[variant].Rationale.Value = plural;
+ }
+ else {
+ game.Rationale.PluralString = reader.ReadElementString ();
+ game.Rationale.Value = plural;
+ }
+ }
+ else {
+ if (processing_variant)
+ game.Variants[variant].Rationale.String = reader.ReadElementString ();
+ else
+ game.Rationale.String = reader.ReadElementString ();
+ }
break;
case "answer":
case "_answer":
diff --git a/tools/GameXmlGetStringTemplate.cs b/tools/GameXmlGetStringTemplate.cs
new file mode 100644
index 0000000..6c033e0
--- /dev/null
+++ b/tools/GameXmlGetStringTemplate.cs
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 Jordi Mas i Hernà ndez <jmas softcatala org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+using System;
+using Mono.Unix;
+
+// This is an auto-generated file GameXmlToGetString tool. Do not edit manually
+public class GameXmlSttringFactory
+{
+ void LoadStrings ()
+ {
+ int variable = 0;
+ STRINGS@
+ }
+}
+
+
diff --git a/tools/GameXmlToGetString.cs b/tools/GameXmlToGetString.cs
new file mode 100644
index 0000000..0abead1
--- /dev/null
+++ b/tools/GameXmlToGetString.cs
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 Jordi Mas i Hernà ndez <jmas softcatala org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+using System;
+using System.Text;
+using System.IO;
+using System.Collections.Generic;
+
+using gbrainy.Core.Main.Xml;
+
+public class GameXmlToAssembly
+{
+ static readonly string output = "GameXmlGetString.cs";
+ static readonly string games = "../data/games.xml";
+ static readonly string template = "GameXmlGetStringTemplate.cs";
+
+ static void Main (string[] args)
+ {
+ Dictionary <string, string> tokens = new Dictionary <string, string> ();
+ StringBuilder strings = new StringBuilder ();
+ GamesXmlFactory factory;
+ TextWriter tw;
+ string file, games_file, template_file, output_file, str;
+ int cnt = 0;
+
+ output_file = args.Length > 1 ? Path.Combine (args[1], output) : output;
+
+ tw = new StreamWriter (output_file);
+ factory = new GamesXmlFactory ();
+
+ games_file = args.Length > 0 ? Path.Combine (args[0], games) : games;
+ factory.Read (games_file);
+
+ // Build GetStrings
+ foreach (GameXmlDefinition definition in factory.Definitions)
+ {
+ if (definition.Question != null) {
+ str = GetStringFromDefinition (definition.Question);
+ if (String.IsNullOrEmpty (str) == false) {
+ strings.AppendLine (str);
+ cnt++;
+ }
+ }
+
+ if (definition.Rationale != null) {
+ str = GetStringFromDefinition (definition.Rationale);
+ if (String.IsNullOrEmpty (str) == false) {
+ strings.AppendLine (str);
+ cnt++;
+ }
+ }
+
+ foreach (GameXmlDefinitionVariant variant in definition.Variants)
+ {
+ if (variant.Question != null)
+ {
+ str = GetStringFromDefinition (variant.Question);
+ if (String.IsNullOrEmpty (str) == false) {
+ strings.AppendLine (str);
+ cnt++;
+ }
+ }
+
+ if (variant.Rationale != null)
+ {
+ str = GetStringFromDefinition (variant.Rationale);
+ if (String.IsNullOrEmpty (str) == false) {
+ strings.AppendLine (str);
+ cnt++;
+ }
+ }
+ }
+ }
+
+ tokens.Add ("@STRINGS@", strings.ToString ());
+
+ // Replace tokens
+ template_file = args.Length > 0 ? Path.Combine (args[0], template) : template;
+
+ string line;
+ Stream read = File.OpenRead (template_file);
+ StreamReader sr = new StreamReader (read);
+ while (true)
+ {
+ line = sr.ReadLine ();
+ if (line == null)
+ break;
+
+ foreach (string token in tokens.Keys)
+ {
+ line = line.Replace (token, tokens[token]);
+ }
+ tw.WriteLine (line);
+ }
+ read.Close ();
+ tw.Close ();
+
+ Console.WriteLine ("gbrainy's GameXmlToGetString, {0} strings extracted", cnt);
+ }
+
+ static string GetStringFromDefinition (LocalizableString localizable)
+ {
+ if (localizable.IsPlural () == false)
+ return null;
+
+ return String.Format ("\t\tCatalog.GetPluralString (\"{0}\",\n\t\t\t\"{1}\",\n\t\t\t{2});\n",
+ localizable.String,
+ localizable.PluralString,
+ "variable");
+ }
+}
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..8c99c83
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,23 @@
+EXTRAFLAGS = $(CSC_DEFINES)
+
+GAMESXMLSTRINGS_CSFILES = \
+ $(srcdir)/GameXmlToGetString.cs
+
+ASSEMBLIES = \
+ -r:../src/gbrainy.Core.dll \
+ -r:Mono.Posix
+
+GameXmlToGetString.exe: $(GAMESXMLSTRINGS_CSFILES) ../data/games.xml $(srcdir)/GameXmlGetStringTemplate.cs
+ $(CSC) -target:winexe -out:$@ $(EXTRAFLAGS) $(GAMESXMLSTRINGS_CSFILES) $(ASSEMBLIES)
+ export MONO_PATH=../src && $(MONO) $@ $(srcdir)
+
+all: GameXmlToGetString.exe
+
+EXTRA_DIST = $(GAMESXMLSTRINGS_CSFILES) $(srcdir)/GameXmlGetStringTemplate.cs $(srcdir)/GameXmlGetString.cs
+
+CLEANFILES = GameXmlToGetString.exe \
+ GameXmlGetString.cs
+
+DISTCLEANFILES = \
+ Makefile
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]