Categories
code development programming

Translations with React, Redux and Asp.Net

In a recent project, which was the first time I’ve used React and Redux in anger, we had a requirement to support 2 different languages, in the .Net backend for emails and PDFs, and in the React frontend.

As the translators we used were used to resx files, we wanted to use those as the master source. In other projects we’ve done the javascript translations via a pre-compilation step into static javascript files, but since redux has it’s own store, I decided to see if we could use that to store and process the translations.

This approach has the advantage that we can use the redux state to translate the site automatically when a new language is selected, without having to reload any pages. For an application that depends on up-to-date data, and had to operate on por data connections, avoiding reloads is essential.

The redux examples shown here use TypeScript, which certainly helped in our development process, but there’s a lot of gotchas getting the dotnet new react-redux template and many 3rd party react and redux libraries working nicely with TypeScript. You can make it work, but it’s definitely not an out-of-the-box solution in most cases.

The solution consists of 3 parts:

  1. The Asp.Net Core 2.0 controller to translate the resx data into JSON (in this example, the resource file is called UserFacingStrings.resx and the default is en-US,
  2. The Redux configuration to retrieve the data and populate it into the store; and
  3. A React function that reads the translation from the store and presents it to the user.

The solution below attempts to get the localisation from the user headers, so you’ll need to enable localisation in your Startup.cs, but depending on your use case, you may want save user language settings in the user’s account data, or in a cookie or other storage in their browser.

ASP.Net Core API controller

[Produces("application/json")]
[Route("api/Localisation")]
public class LocalisationController : Controller
{
    private static Dictionary _cultureCache = new Dictionary();

    /// Get all known translations
    /// Choose a culture (e.g. `en-US` )
    /// will default to browser culture if not specified
    [HttpGet("[action]/{culture?}")]
    public IActionResult Translations(string culture)
    {
        try
        {
            var cultureInfo = CultureInfo.CurrentUICulture;
            try
            {
                string preferredLanguage = HttpContext.GetPreferredLanguage();
                if (!string.IsNullOrWhiteSpace(culture))
                {
                    cultureInfo = CultureInfo.GetCultureInfo(culture);
                }
                else if (!string.IsNullOrWhiteSpace(preferredLanguage))
                {
                    cultureInfo = CultureInfo.GetCultureInfo(preferredLanguage);
                }
            }
            catch (CultureNotFoundException)
            {
                // Fallback to en-US
            }

            if (_cultureCache.Keys.Contains(cultureInfo.ToString()))
            {
                return new OkObjectResult(new { t = _cultureCache[cultureInfo.ToString()] });
            }

            var translations = new Dictionary();

            // Insert all resources, to then be overwritten
            if (cultureInfo.TwoLetterISOLanguageName != "en")
            {
                ExtractResources(translations, UserFacingStrings.ResourceManager.GetResourceSet(CultureInfo.GetCultureInfo("en-US"), true, true));
            }

            ExtractResources(translations, UserFacingStrings.ResourceManager.GetResourceSet(cultureInfo, true, true));

            _cultureCache[cultureInfo.ToString()] = translations;

            return new OkObjectResult(new { t = translations });
    }
    catch (Exception)
    {
        return NotFound();
    }
}

private static void ExtractResources(Dictionary translations, ResourceSet resourceSet)
{
    foreach (DictionaryEntry res in resourceSet)
    {
        translations[res.Key.ToString()] = res.Value.ToString();
    }
}

Browser Extension

public static class BrowserDetailsExtensions
{
    public static string GetPreferredLanguage(this HttpContext http)
    {
        return http?.Request
            ?.Headers["Accept-Language"].ToString()
            ?.Split(',').FirstOrDefault()
            ?.Split(';').FirstOrDefault();
    }
}

Redux plumbing

CultureActions.ts

import { AppThunkAction } from '../store/index';
import { fetch } from 'domain-task';
import { CALL_API } from 'redux-api-middleware';
import { actionCreatorFactory } from 'typescript-fsa';
import { Translations } from '../reducers/CultureState';
import { Dictionary } from 'lodash';

const API_ADDRESS: string = "/api/Localisation/";
const API_GET_TRANSLATIONS: string = "Translations/";
const API_LANGUAGE_CODE: string = ""; // "pt-BR", "en-GB"
const API_REQUEST_TYPE_GET: string = "GET";

export interface ApiError {
    name: 'ApiError',
    status: number,
    statusText: string,
    response: string
}

export interface GetTranslationsAction {
    type: 'RECEIVE_TRANSLATIONS';
    t: Dictionary;
};

export interface TranslationsApiPosted {
    type: 'Translations_REQUEST_POSTED';
    payload: never;
};

export interface TranslationsApiFailed {
    type: 'Translations_FAILURE';
    payload: ApiError;
    error: true;
};

export interface TranslationsApiSuccess {
    type: 'Translations_SUCCESS';
    t: Dictionary;
}

// Declare a 'discriminated union' type. This guarantees that all references to 'type' properties contain one of the
// declared type strings (and not any other arbitrary string).
export type CultureAction = GetTranslationsAction;

const actionCreator = actionCreatorFactory();
export const translationsAwaitingResponse = actionCreator('Translations_REQUEST_POSTED');
export const translationsSuccess = actionCreator('Translations_SUCCESS');
export const translationsFailure = actionCreator('Translations_FAILURE');

// ACTION CREATORS don't directly mutate state, but they can have external side-effects (such as loading data).
export const cultureActions = {
    getTranslations: (): AppThunkAction => (dispatch, getState) => {
        console.log("REQUEST TRANSLATIONS ACTION")
        const rsaaRequestAuctions = {
            [CALL_API]: {
                credentials: 'same-origin',
                endpoint: API_ADDRESS + API_GET_TRANSLATIONS + API_LANGUAGE_CODE,
                method: API_REQUEST_TYPE_GET,
                types: ['Translations_REQUEST_POSTED', 'Translations_SUCCESS', 'Translations_FAILURE']
            }
        }
        dispatch(rsaaRequestAuctions);
    },
};

CultureStore.ts and the tr() method

import { Dictionary } from "lodash";
import * as He from 'he';
import { Decimal } from "decimal.js";

export type CultureState = {
    strings: Translations
};

export interface Translations {
    t: Dictionary
};

export const emptyCulture: CultureState = {
    strings: {
        t: {}
    }
};

export function tr(culture: CultureState, key: string): string {
    try {
        return He.decode(culture.strings.t[key]) || key;
    } catch (error) {
        console.log("translation for '" + key + "' not found");
        if (key == undefined || key == null) {
            return "- -";
        }
        return "-".repeat(key.length);
    }
}

// Returns the key value itself if no match is found in the resx
export function trFallback(culture: CultureState, key: string): string {
    try {
        return He.decode(culture.strings.t[key]) || key;
    } catch (error) {
        return key;
    }
}

export function trFormat(culture: CultureState, key: string, args: string[]): string {
    return formatString(tr(culture, key), args);
}

export function formatDecimalAmount(subject: Decimal): string {
    return formatAmount(subject.toNumber());
};

export function formatAmount(subject: number): string {
    return subject.toLocaleString(navigator.language, { maximumFractionDigits: 2 });
};

function formatString(subject: string, args: string[]): string {
    if (subject === undefined) {
        return "";
    }
    return subject.replace(/{(\d+)}/g, function (match, number) {
        return typeof args[number] != 'undefined'
            ? args[number]
            : match
        ;
     });
};

CultureReducer.ts

import { Action, Reducer } from 'redux';
import { isType } from 'typescript-fsa';
import { Translations, emptyCulture, CultureState } from './CultureState';
import { ApiError, CultureAction, translationsAwaitingResponse, translationsFailure, translationsSuccess } from '../actions/CultureActions';
import { Dictionary } from 'lodash';

export interface CultureStateR extends CultureState { }

const unloadedState: CultureStateR = emptyCulture;

export const reducer: Reducer = (state: CultureStateR, incomingAction: Action) => {
    const action = incomingAction as CultureAction;

    if (typeof state === undefined) {
        return unloadedState;
    }

    if (isType(incomingAction, translationsAwaitingResponse)) {
        return {
            strings: state.strings
        };
    }
    if (isType(incomingAction, translationsFailure)) {
        return {
            strings: state.strings
        };
    }
    if (isType(incomingAction, translationsSuccess)) {
        const rawTranslations: Dictionary = incomingAction.payload.t;
        return {
            strings: { t: rawTranslations }
        };
    }

    switch (action.type) {
        case 'RECEIVE_TRANSLATIONS':
            return state;

        default:
            break;
    }

    return state || unloadedState;
}

Use in account controller

import { CultureState, tr } from '../reducers/CultureState';
/// Some imports removed for clarity

/// Add CultureState into props for this component
type AccountProps = AccountState & CultureState & typeof accountActions & RouteComponentProps;

export class Account extends React.Component {
}

Use tr() in view tsx file

</pre>
<h2>{tr(this.props, "PersonalDetails")}</h2>
<table>
<tbody>
<tr>
<td>{tr(this.props, "Name")}:</td>
<td>{this.props.user.userName}</td>
<td><a href="/account/profile">{tr(this.props, "Edit")}</a></td>
</tr>
<tr>
<td>{tr(this.props, "Company")}:</td>
<td>{this.props.user.companyName}</td>
</tr>
<tr>
<td>{tr(this.props, "Email")}:</td>
<td>{this.props.user.emailAddress}</td>
</tr>
</tbody>
</table>
<pre>
Categories
.net development programming

My .net journey

With the release of Visual Studio 2017 and .net core, I’ve seen a few folk talking about their story with the platform. This is mine.

I’ve never been the biggest Microsoft fan, ever since I grabbed a copy of Mandrake Linux and figured out how much more tinkering was available and how much more logical certain operations were than on Windows 95. But it was definitely still a tinkerers platform.

But I got an internship at Edinburgh University whilst I was a student there, funded by Microsoft. I got a laptop for the summer and a iPaq (remember that?) to keep. I also got a trip to Amsterdam to meet the other interns and some folk from Microsoft, back before they had much more than sales people in the UK. And they told me, no matter how much anyone hates Microsoft, they always hate Oracle more.

It meant that I was among the first to get the .net 1.0 CD, so I could legitimately claim later that yes, I did have 2 years of .net experience.

But from there, I stayed in Linux, learning the joys of Java Threading on Solaris (top tip : Sun really should have known what they were doing, that they didn’t means I can see some of why they failed – it was far¬†easier working with threads on Red Hat or Windows).

And then I did my PhD, digging into device drivers, DirectX and MFC. I hated Microsoft’s Win32 GUI stuff, but the rest, in C++, was quite nice. I enjoyed being closer to the metal, and shedding the Java ceremony. I trained on templates and started to understand their power. And Java just wasn’t good enough.

I wrote research projects in C++ and data analysis engines in Python. It was good.

But Java came back, and I wrote some media playback for MacOS, and fought iTunes to listen to music. And I vowed never to buy from Apple because both were a right pain.

And I needed a new job. And I’d written bots in IronPython against C#, so I got a .Net job. And I missed the Java and Python communities, the open source chatter. And I wanted to write code in C# that was as beautiful and testable as C++. And I wanted to feel that Bulmer’s Developers! chant was a rallying call, not a lunch order from a corporate monster.

So I found alt.net and it was in Scotland, and I wrote a lot of code, and I learned that open source did exist in c#, and that there was a conference named after that chant and I met more like minded developers. I fought my nervousness and my stumbling voice and I found some confidence to present. And blog. And help write a package manager. And then everyone else learned Ruby.

And then the Scotts joined Microsoft and alt.net became .net. And then LINQ came and I remembered how clean functional programming is, and I started feeling like I was writing Python if I squinted hard, and ignored types. And then core came, and Microsoft had some growing pains. But it’s a sign that the company has completely shifted in the right direction, learning from the guys who left for Ruby. And Node.

I’m proud of what I’ve built in C#, and it’s a much better language than Java, now. It’s definitely the right choice for what I’ve built. The documentation is definitely better than Apple or Sun/Oracle produce, although MSDN and docs.microsoft.com are having some migration pains of its own.

And alt.net is making a comeback.

And I still use Python on hobby projects.

Categories
code development ux

Your API sucks : verbosity

The more complicated your API, the easier it is for developers to make a mistake. Make it easy to do the right thing. If you have to create an order before submitting it, make the order itself the required context for submission. In a library, make Submit() a method on the class. In a RESTful web service, make the submission POST against the URI of the order you are submitting.

Limit user options. Choose sensible defaults that can be overridden if, and only if, requested. Think about sending an email. By default it’s not important, there’s no BCC, the reply-to address is your address. You don’t have to think about them unless you need them.

Compare that to the C++ Win32 API, which is partly a C++ problem, and partly a Windows problem. Look at the prerequisites you need to follow, look at how many NULL arguments there are, look at how much error checking is required.

Walkthrough: Creating Windows Desktop Applications (C++)

And then compare it with the Python TkInter Hello World example, which leans on a lot of defaults, and packages up most of the prerequisites inside the API.

Python TkInter – 24.1.2.2. A Simple Hello World Program

Categories
.net code development

Naming things is hard – Microsoft’s Core problem

There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors.

Microsoft are changing the name of the next iteration of .Net – what was .Net 5.0 is now .Net Core 1.0, and like Rick Strahl, I like the idea, but I’m not find of the timing. Although, as it’s pre-release, anyone writing production code on it was playing with fire anyway. I’m not a big fan of the naming scheme though.

The timing issue is an easy one to solve. I’ve had projects running under placeholder codewords for months whilst the business agreed a proper name. Microsoft has been doing this for years. No-one expected to see Windows Chicago, Windows Threshold or SQL Server Denali. No-one would have expected to ship .Net Sapphire (hey, they’ve admitted that were going after the Ruby developers ūüėČ ) Everyone knew they were codewords, to be replaced pre-release once marketing figured out what year it was being released – or the regression testers discovered how much old code thought 9 < 7.

The problem I have with it is that ASP.Net Core sounds like part of the family that includes ASP.Net MVC, ASP.Net SignalR or ASP.Net AJAX, whereas it actually replaces the ASP.Net part with its own .Net Core stack. I can’t at the moment think of a better way to name the ASP.Net Core though, without losing the ASP.Net brand.

The naming works when you compare .Net Framework to .Net Core, and to me it’s as natural as when Netscape open sourced Navigator to give us Firefox (once they managed to choose a unique name). It was from some of the same team, and it did the same job, but the new one was leaner, faster and more focused.

Naming things is hard, but starting a new roadmap and resetting expectations is definitely the right thing to do. .Net and the ASP.Net frameworks have needed a decent overhaul for a while to fix the untestable, interdependent ball of mud that the .Net framework install had become. I like the new Core world, with NuGet and Gulp and Grunt, and Github at the heart of development. This is not a Microsoft I thought I’d see when I was at the ScotAlt.Net meetings all those years ago.

Alt.Net is dead. Long live .Net Core.

Categories
development

Google Code Migration : Genetic Algorithm Templates

With the closure of Google Code, I’ve moved some projects to github. All personal projects so far, but related to talks our blog posts from the past, so may still be of interest.

The first project I want to highlight again is written in C++ and implements genetic algorithms using mainly C++ templates, just to see how powerful they were. It taught me a lot about generic code, and how a poor type system can interfere with the clarity of your code. It also prepared me for one of my first talks, about Genetic Algorithms at a Beauty of Code techmeetup.

I’d like to look at a Python port, to see if my expectations of using dynamic typing would answer the concerns I have about code clarity. For now though, it’s available for reference. It’s not production tested, and there are parts that are embarrassing, but it might be interesting if you want to know what genetic algorithms might look like.

Categories
code development

Cognitive load : fluent interfaces and friendly apis

a friendly robot, sitting down
Is your interface friendly?

To continue my mini series on cognitive load, following my previous post on static vs extension methods, a couple more examples to consider. Extension methods are often used as an entry point into a fluent interface, allowing a style which can be easier to read and eliminate the need for confusing, overly long parameter lists, multiple overloads or parameter objects.

They can also be used to humanize the interface, based on the understanding that the user experience of an API should be as important as the user experience of a website or application.

In the first example, I put together a quick concept for date comparison, to see if a fluent style is more readable than arithmetic operations on dates. Decide for yourself if that’s true. I discovered that making fluent operators is often harder than usual naming considerations, especially when the same word can be used to mean subtly different things.

In the second example, which I found fascinating, chaining is used to turn a conventional c# method into something more akin to a functional language with the intent of making the operations clearer and refocusing unnecessary interim storage steps. I’m not sure this is always the best approach, but I’ll definitely be adding these helper methods to my toolkit.

Categories
code development

Cognitive load : static vs extension methods

Cheese board sitting on cans of tomatoes
Extending tools beyond their original purpose

A c# specific example to follow up my blog post on cognitive load, since it coincidentally came up at work.

What are extension methods?

The example concerns c# extension methods. For those of you who aren’t C# developers, they allow you to create a static method that can be called as if it was a class method, without needing to modify the original class. They’re mainly useful for extending classes or basic types with new functionality, such as business-specific rules. For example, the LINQ library extends IEnumerable types with a number of functions, including Where() which provides the filter functionality found in functional programming, allowing users to write code like:

int[] array = {2, 3, 4, 5, 1};
return array.Where(x => x % 2 == 0); 
// returns {2, 4}

The x => x % 2 == 0 in the above snippet is a lambda expression that takes an input x (for the Where method, each member of the array) and returns the result of the expression on the right of the arrow.

LINQ example

The discussion centred around whether extension methods like the above were preferable to code using static methods such as :

int[] array = {2, 3, 4, 5, 1};
return Where(array, x => x % 2 == 0);
// returns {2, 4}

As you can see, here array is passed as the first argument (which is what extension methods do behind the scenes).

The example I raised looked like the following, where a number of these methods are chained together. Note that all the methods return a new result, as they are built to allow immutable collections, such as input buffers.

Static methods

filteredthing = Linq.Where(thing, x => x.Deleted == false);
orderedthing = Linq.OrderBy(filteredthing, x => x.CreatedDate);
result = Linq.Select(orderedthing, x => new y(x.Name, x.Id)); 

Chained extension methods

thing.Where(x => x.Deleted == false)
    .OrderBy(x => x.CreatedDate)
    .Select(x => new y(x.Name, x.Id)); 

I argued that the former requires more thought, and therefore a higher cognitive load to understand which variable to use, and the density of code requires makes it less readable and therefore makes the next developer’s job harder.

String example

The most interesting example however, was the one that started the discussion. Which of the following forms do you prefer, and why?

mystring.IsNullOrEmpty()

or

String.IsNullOrEmpty(mystring)

In particular, note that we don’t have the variable or code proliferation as in the LINQ example, and the return value is an explicitly different type.

The most persuasive argument I heard against the extension method version is that it explicitly works when mystring is null, which leads to a counterintuitive situation where, as developers, we are trained to spot potential NullReferenceException problems, and will immediately view the first form with suspicion, until we realise it is an extension method.

Question

Which form do you prefer, and would either one stop you in your tracks as you were scanning code and break your train of thought.

Categories
c++ code development programming

Chimera wishlist : !NullReferenceException

What features from other languages do you wish your main development language had?

As someone whose first real applications were written in C++, the thing that always bugged me about C# and Java (after they got generics and autoboxing sorted) was the way they handled references. In my C++ mind, C# and Java pass pointers around, and pointers are allowed to be null. So every single time I have to use them, I have to check them for null, or set up the caller to make sure they’re not null. As Anders Hejlsberg points out, that single fact causes more problems than anything else in C#.

Also, I wish C# allowed const references like C++ to guarantee an object isn’t modified within a method when passing by reference, which is always useful to avoid copying large objects. C# would have to support const methods too, of course.

50% of the bugs that people run into today, coding with C# in our platform, and the same is true of Java for that matter, are probably null reference exceptions. If we had had a stronger type system that would allow you to say that ‘this parameter may never be null, and you compiler please check that at every call, by doing static analysis of the code’. Then we could have stamped out classes of bugs.

But peppering that on after the fact once you’ve built a whole platform where this isn’t built in‚Ķ it’s very hard to pepper on afterwards. Because if you start strengthening your APIs and saying that you can’t pass null here or null here or null here, then all of a sudden you’re starting to break a bunch of code. It may not be possible for the compiler to track it all properly.

Anyway, those are just things that are tough later. You sort of end up going, well ok, if we ever get another chance in umpteen years to build a new platform, we’ll definitely get this one right. Of course then we’ll go and make other mistakes! But we won’t make that one.

http://www.computerworld.com.au/index.php/id;1149786074;pp;3

So, what do you wish for?

Categories
code development krugle programming

Adding HTTP Headers to WaTiN tests

EDIT (2010-08-17 21:26 GMT) : I found a bug in the COM interop that prevented the code from compiling on certain machines. This has now been fixed so if you copied this code before, please try it again.

It’s taken me a while to figure this one out, so I’m putting up a post in case anyone else has a problem. In our system, we need to inject specific headers into each request to simulate our live environment, which means either injecting those expected headers into our tests or having different controller behaviour for dev and live environments.

WaTiN is great for all the other tests we do, but it doesn’t currently support adding HTTP headers to a request, and after a look through the source code, I can see the hoops they’d have to jump through to make it cross-browser. For our purposes, we just needed IE support, so we have the option of intercepting the events on the IE instance directly.

MyHeaders is a property of type object for COM interoperability. It uses the SHDocVw dll to interact with IE. If you allow MyHeaders to be null, you will get an infinite loop and a StackOverflow. I will not guarantee anything about this code, but I hope it’s one small step towards native WaTiN cross-browser HTTP headers support. I am happy to hear about any success you have using or extending this. I will leave setting of test-specific values and compatibility for other browsers as an exercise for the reader.

Snippet

        private object MyHeaders { get; set; }

        private void beforenavigate2replaceheaders(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
        {
            if (Headers == null)
            {
                Cancel = true;
                object objTestHeaders = MyHeaders;
                _ieInstance.Navigate2(ref URL, ref Flags, ref TargetFrameName, ref PostData, ref objTestHeaders);
            }
        }
 
        private void beforenavigatereplaceheaders(string URL, int Flags, string TargetFrameName, ref object PostData, string Headers, ref bool Cancel)
        {
            if (Headers == null)
            {
                Cancel = true;
                object objFlags = Flags;
                object objTargetFrameName = TargetFrameName;
                object objTestHeaders = MyHeaders;
                _ieInstance.Navigate(URL, ref objFlags, ref objTargetFrameName, ref PostData, ref objTestHeaders);
            }
        }

        private void SetUpBrowser()
        {
            CloseBrowser();
            Settings.AutoMoveMousePointerToTopLeft = false;
            Settings.MakeNewIeInstanceVisible = true;
            Settings.WaitForCompleteTimeOut = 120;

            _ieInstance = new SHDocVw.InternetExplorerClass();
            MyHeaders = "Content-Type: application/json\r\n";
            ((SHDocVw.InternetExplorerClass)_ieInstance).BeforeNavigate += beforenavigatereplaceheaders;
            ((SHDocVw.InternetExplorerClass)_ieInstance).BeforeNavigate2 += beforenavigate2replaceheaders;
            _browser = new IE(_ieInstance) { AutoClose = true });
        }
            
Categories
code programming

July Tech Meetup Glasgow: The Beauty of Code – Techmeetup

The video for my Genetic Algorithm talk has been posted to the TechMeetup blog for those who want to watch it (and can withstand my stuttering ūüėČ ). If you want to grab the original presentation itself, it’s in the repository for the C++ template project: geneticalgorithmtemplates \ talks and presentations \ techmeetup glasgow 20090701 (edit : now moved to github)

Craig Nicol on Genetic Algorithms

Craig provided a high-level introduction to what genetic algorithms are and how they can be used.Genetic algorithms is a search technique used in computing to find exact or approximate solutions to optimization and search problems. As the name suggests, they’re inspired by the process of evolution in the natural world. The typical genetic algorithm consists of a genetic representation of the solution domain, and a fitness function for evaluating the solution domain.Craig used example to clarify the topic and his presentation stimulated an interesting discussion of potential applications of the technology.

July Tech Meetup Glasgow: The Beauty of Code – Techmeetup

Craig Nicol talks about Genetic Algorithms from TechMeetup on Vimeo.

Hope to see you at the techmeetup talk tonight.

Blogged with the Flock Browser