Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Wire a Configuration to a Service

33 views
Skip to first unread message

Shapper

unread,
Nov 15, 2012, 6:59:40 AM11/15/12
to
Hello,

I am creating a translator as follows:

public interface ITranslator {
String Translate(String text, String fromCulture, String toCulture);
} // ITranslator

Basically, this translates a string from one culture to another.

This is working in a different way from something I asked sometime ago in this newsgroup. I hope I am able to get some advice on this version.

I have a class which holds groups of translations:

public class TranslatorProviderBase {
public List<Dictionary<String, String>> Table { get; private set; }
public TranslatorProviderBase() {
Table = new List<Dictionary<String, String>>();
}
public void Add(Dictionary<String, String> translations) {
Table.Add(translations);
}
} // TranslatorProviderBase

Using this class as base I can place translations in different parts of my application:

public class TranslatorProvider : TranslatorProviderBase {
public TranslatorProvider() {
Add(new Dictionary<String, String> { { "en", "Hello" }, { "pt", "Olá" }, { "fr", "Bonjour" } });
Add(new Dictionary<String, String> { { "en", "Bye" }, { "pt", "Adeus" }, { "fr", "Adieu" } });
}
} // TranslationProvider

I created a class to "save" the providers and the translator configuration:

public class TranslatorConfiguration {
public IList<String> Cultures { get; private set; }
public IList<TranslatorProviderBase> Providers { get; private set; }
public TranslatorConfiguration() {
Cultures = new List<String>();
Providers = new List<TranslatorProviderBase>();
}
public void AddProvider(TranslatorProviderBase provider) {
Providers.Add(provider);
}
public void AddProvider<T>() where T : TranslatorProviderBase, new() {
Providers.Add(new T());
}
public void SetValidCultures(params String[] cultures) {
Cultures = cultures.ToList();
}
} // TranslatorConfiguration

I have a class through which I configure the translator:

public class TranslatorManager {
public static void Initialize(Action<TranslatorConfiguration> configuration) {
configuration.Invoke(new TranslatorConfiguration());
} // Initialize
} // TranslatorManager

NOTE: This class will have other methods like AssertTranslatorConfigurationIsValid, etc.

The translator setup and usage would be something like this:

TranslatorManager.Initialize(x => {
x.AddProvider<TranslatorProvider>();
x.SetValidCultures("en", "pt", "fr");
});
ITranslator translator = new Translator();
String adeus = translator.Translate("Bye", "en", "pt");

PROBLEMS:

1 - My main problem, at the moment, is how to wire the Translator, implementation of ITranslator, to the TranslatorConfiguration so I can access providers and values in Translator.

2 - I think I should also allow to register the container in configuration and have some kind of factory to wire things ... But I am not sure if yes and how.

My Translator, implementation of ITranslator, is the following:

public class Translator : ITranslator {

public String Translate(String text, String fromCulture, String toCulture) {

foreach (TranslatorProviderBase provider in TranslatorConfiguration.Providers) {

Dictionary<String, String> row = provider.Table.First(x => x.Any(y => y.Key == fromCulture && y.Value == text));
if (row == null)
return null;

String translation;
if (row.TryGetValue(toCulture, out translation))
return translation;

}
return String.Empty;
} // Translate

} // Translate

See how I am using "TranslatorConfiguration.Providers" in my foreach loop.

Of course this does not work unless I make TranslatorConfiguration as static as well as its methods and properties.

But then I get the following errors in TranslatorManager:

'TranslatorConfiguration': static types cannot be used as type arguments

Cannot create an instance of the static class

I have seen a few libraries 'working' this way but I am not sure how to wire the configuration values (TranslatorConfiguration) to the service (Translator).

Thank You,

Miguel

bradbury9

unread,
Nov 15, 2012, 12:25:16 PM11/15/12
to
[Serializable]
public class Culture
{
public string Name {get; set;}
internal Dictionary<string, string> keys {get; set; }
public Culture(string name)
{
this.Name = name;
this.keys = new Dictionary<string,string>();
}

public string getValue(string key)
{
return keys[key];// TODO: check null references
}

public void addKey(string key, string value)
{
keys.Add(key, value); // Check if it already existed
}
public string getKey(string value)
{
return keys.Where(p => p.Value == value).First().Key; // Change, could not be found
}
}

public abstract class TranslatorBase
{
protected abstract List<Culture> Cultures {get; }
public void addKey(string key, Dictionary<string, string> values)
{
foreach(Culture culture in this.Cultures)
{
culture.addKey(key, values[culture.Name]);
}
}
public string TranslateKey(string key, string destinationCulture)
{
Culture destination = this.Cultures.Where(p => p.Name == destinationCulture).First();
return destination.getValue(key);
}
public string TranslateValue(string value, string sourceCulture, string destinationCulture)
{
Culture source = this.Cultures.Where(p => p.Name == sourceCulture).First();
Culture destination = this.Cultures.Where(p => p.Name == destinationCulture).First();
string key = source.getKey(value);
return destination.getValue(key);
}
}

public class TranslatorExample : TranslatorBase
{
private static List<Culture> _Cultures;
protected override List<Culture> Cultures
{
get
{
if(TranslatorExample._Cultures == null)
{
TranslatorExample._Cultures = new List<Culture>();
TranslatorExample._Cultures.Add(new Culture("es"));
TranslatorExample._Cultures.Add(new Culture("us"));
TranslatorExample._Cultures.Add(new Culture("uk"));
}
return TranslatorExample._Cultures;
}
}
}


static void Main(string[] args)
{
TranslatorExample example = new TranslatorExample();

Dictionary<string,string> userValues = new Dictionary<string,string> { { "es", "Nombre de usuario" }, { "us", "User name" }, { "uk", "User" } };
example.addKey("userName", userValues);

Console.WriteLine(example.TranslateKey("userName", "es")); // Nombre de usuario
Console.WriteLine(example.TranslateKey("userName", "us")); // User name

Console.WriteLine(example.TranslateValue("User name", "us", "es")); // Nombre de usuario
Console.WriteLine(example.TranslateValue("User name", "us", "uk")); // User

Console.ReadLine();
}

bradbury9

unread,
Nov 15, 2012, 3:54:31 PM11/15/12
to
I know i rewite most code from scratch but... I tagged Culture as Serializable, so you only have to:
a) Move "static List<Culture> _Cultures;" to TranslatorBase.
b) Add a serialization method to TranslatorBase.

Then it will fit your needs, i guess.

Shapper

unread,
Nov 15, 2012, 5:38:42 PM11/15/12
to
Hello,

I liked your approach of translating a value by Key or Value.

However, there was a reason for each class in my design:

1 - ITranslator and Translator

I need to inject ITranslator in parts of the application using IOC.

2 - TranslatorConfiguration

I need to be able to "configure" how the translator works:

A) Define DefaultCulture.
When fromCulture is not specified DefaultCulture will be used

B) Define RequiredCultures
Basically I will define which cultures to use.

I will need these values in TranslateMethods ...
And also in other methods like TranslatorConfiguration.AssertIsValid.
This will test if all provides contains all cultures or each value.

And probably others ..

Maybe my design is not the best one but I am trying to be able to have this ...

And also with TranslateKey and TranslateValue which I think is really useful.

Thank You,
Miguel

Arne Vajhøj

unread,
Nov 19, 2012, 9:38:23 PM11/19/12
to
On 11/15/2012 6:59 AM, Shapper wrote:
> I am creating a translator as follows:
>
> public interface ITranslator {
> String Translate(String text, String fromCulture, String toCulture);
> } // ITranslator
>
> Basically, this translates a string from one culture to another.
>
> This is working in a different way from something I asked sometime ago in this newsgroup. I hope I am able to get some advice on this version.
>
> I have a class which holds groups of translations:
>
> public class TranslatorProviderBase {
> public List<Dictionary<String, String>> Table { get; private set; }
> public TranslatorProviderBase() {
> Table = new List<Dictionary<String, String>>();
> }
> public void Add(Dictionary<String, String> translations) {
> Table.Add(translations);
> }
> } // TranslatorProviderBase
>
> Using this class as base I can place translations in different parts of my application:
>
> public class TranslatorProvider : TranslatorProviderBase {
> public TranslatorProvider() {
> Add(new Dictionary<String, String> { { "en", "Hello" }, { "pt", "Ol�" }, { "fr", "Bonjour" } });
> Add(new Dictionary<String, String> { { "en", "Bye" }, { "pt", "Adeus" }, { "fr", "Adieu" } });
> }
> } // TranslationProvider

I do not see any reason why to extend the class here instead of just
having the client code Add to TranslatorProviderBase (which in that case
probably should just be called TranslatorProvider).

> I created a class to "save" the providers and the translator configuration:
>
> public class TranslatorConfiguration {
> public IList<String> Cultures { get; private set; }
> public IList<TranslatorProviderBase> Providers { get; private set; }
> public TranslatorConfiguration() {
> Cultures = new List<String>();
> Providers = new List<TranslatorProviderBase>();
> }
> public void AddProvider(TranslatorProviderBase provider) {
> Providers.Add(provider);
> }
> public void AddProvider<T>() where T : TranslatorProviderBase, new() {
> Providers.Add(new T());
> }
> public void SetValidCultures(params String[] cultures) {
> Cultures = cultures.ToList();
> }
> } // TranslatorConfiguration

What value does this class have? If none then get rid of it.
You translator needs to get an IList<TranslatorProviderBase> in as
constructor argument or via setter, save it in a field and then
just use it.

Arne

0 new messages