turquoiseowl / i18n

Smart internationalization for ASP.NET
Other
556 stars 156 forks source link

Using i18n outside of a web context #346

Closed ajbeaven closed 5 years ago

ajbeaven commented 6 years ago

What's the likelihood of adding support so this library could be used outside of a web context? I note ParseAndTranslate is tied to a instance of HttpContextBase or HttpContext but I'd love be able to use this in a console app.

turquoiseowl commented 6 years ago

Thanks for the question but not much chance I'm afraid, mainly because the essence of this library is hooking into the request/response pipeline to make the translations (obviating the need for the _() function).

There is another GetText library for C# general apps that works like the original GetText i.e. with _() functions etc.. Version 1 of this lib also worked like that.

ajbeaven commented 6 years ago

The console app is embedded as a part of a website that uses this library (in fact it also generates the po files that the console app would use) which is why I'm pretty keen to not have to use a separate i18n library.

Presumably there's code somewhere in here that does the work I'd need so provided things are not marked internal I'm hoping I'll be able to make it work. If you have any advice with where to start that be very much appreciated otherwise I'll happily stumble along by myself. Thanks so much for the work you've put in to this great resource!

turquoiseowl commented 6 years ago

A good place to start might be the ParseAndTranslate extension method to HttpContext which is mentioned in the readme.

Thinking aloud, you could mock an HttpContext instance a bit like you would in a unit test, set up a static instance of that in your console app that takes input equivalent to the Accept-Language HTTP header, then wrap your nuggets in a translation function (e.g. called _ ) that relays on to HttpContext.ParseAndTranslate. Something like this:

static string _(string msgWithNuggets)
{
    return s_http_context_mock.ParseAndTranslate(msgWithNuggets);
}

which you would then call like

    Console.WriteLine(_("[[[translate me///comment]]] but not me"));

(That helper would need to be in a static class I guess.)

Good luck and let us know how you get on and we could look at adding your solution to the lib.

ajbeaven commented 6 years ago

So I ended up hacking up an instance of NuggetLocalizer and calling ProcessNuggets instead of mocking the HttpContext.

var i18nSettings = new i18nSettings(new AppConfigSettingService());
var translationRepository = new POTranslationRepository(i18nSettings);
var textLocalizer = new TextLocalizer(i18nSettings, translationRepository);
var nuggetLocalizer = new NuggetLocalizer(i18nSettings, textLocalizer);
var languageItems = new[] { new LanguageItem(new LanguageTag("en"), LanguageItem.PalQualitySetting, 0) };

var translatedText = nuggetLocalizer.ProcessNuggets("[[[translate me]]] but not me", languageItems);

Unfortunately AppConfigSettingsService was necessary as the existing WebConfigSettingsService only works (unsurprisingly) with web.config whereas I needed to use app.config in my console app.

public class AppConfigSettingService : AbstractSettingService
{
    public AppConfigSettingService(string configFileLocation = null) 
        : base(configFileLocation)
    {
    }

    public override string GetConfigFileLocation()
    {
        return AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
    }

    public override string GetSetting(string key)
    {
        return ConfigurationManager.AppSettings[key];
    }

    public override void RemoveSetting(string key)
    {
        throw new NotImplementedException();
    }

    public override void SetSetting(string key, string value)
    {
        throw new NotImplementedException();
    }
}

As an aside, I'm not entirely sure why WebConfigSettingsService doesn't make use of ConfigurationManager.AppSettings as above? It seems to me like it should be pretty easy to make a SettingsService that works with both web.config and app.config but I'll leave that for a future pull request :)

So yeah, nothing in here that is nice enough to put in to the lib, but at least it's documented for others that might need to do some similar hackery.

I'm a little worried about how inefficient this might be. My use case is for translating the content of emails that are sent out via a console app. I'm hoping to send thousands of emails in quick succession and the content is dynamic ("Hi {namehere}") so each email needs to be translated individually. With my use case in mind, if you envision any major issues with the above code, please let me know!

calway commented 6 years ago

@ajbeaven I'm trying to setup a console app with your example but my translations don't get processed. I started an empty console app, added the nuget package, put your sample code in main. put the messages.pot in locale and a translation (messages.po) in an nl sub-fodler. Changed languageItems from en to nl but still the original text is generated. What am I missing. I would also like to use i18n in console apps and windows services so getting this to work would be super

EDIT: Since adding the #: lines in the .pot .po files it worked

turquoiseowl commented 5 years ago

Closing. Please re-open is appropriate. Thanks.