Generate Resx Translations from Google Sheets
In my career, I have tried multiple translation tools for handling localization. This usually ends up in a spreadsheet sent back and forth that gets imported/exported with the actual translation tool. I have also tried giving my translators and customers direct access to the translation tool but that never really worked as they tend to blindly translate everything they see and usually miss out on the fact that some strings contain important placeholders that executable code expects. Anyway, at the end of the sending a spreadsheet back and forth seems to always work.
In a recent project, I built an Android and iOS app with Xamarin.Forms that used Resx files for handling cross platform translations, and InfoPlist.strings files in iOS for localizing OS requirement prompts for using things like Camera, Localization, Photos, etc. For this project we thought about playing around with Google Sheets as a translation tool. Google Sheets has built in Google Translate support so you can do something like =GOOGLETRANSLATE($B2,$B$1,C$1) where $B2 describes the text to translate, $B1 describes the source language, in this case English is the default, and $C1 describes the language to translate to. With this approach, I can very easily, blindly, add new translations to my app, like in this sample Google Sheets document, where I added Danish, German, Filipino, Simplified Chinese, Japanese, and Koreanusing the Google Translate tool. Of course, this needs to be proof-read by a translation professional who mastered the language, but this approach is very convenient for checking out how the app looks like in different languages.
Now here’s the awesome part. My colleague and good friend, Ricky Kaare Engelharth, created a translation tool called csvtrans that can produce Resx, iOS, and Android translation files from a publicly available Google Sheets document. The tool is written in .NET Core and is publicly available from nuget.org as a tool.
The tool can be installed using this command
dotnet tool install -g csvtrans
Using the tool is also straight forward and it also comes with some quick start instructions
USAGE: csvtrans [--help] [--sheet <document id> <sheet name>]
[--csv <url or path>] [--format <apple|android|resx>]
[--outputdir <directory path>] [--name <string>]
[--convert-placeholders <regex pattern>]
OPTIONS:
--sheet, -s <document id> <sheet name>
specify a Google Sheet as input.
--csv, -c <url or path>
specify a online or local cvs file as input.
--format, -f <apple|android|resx>
specify the output format.
--outputdir, -o <directory path>
specify the output directory.
--name, -n <string> specify an optional name for the output.
--convert-placeholders, -p <regex pattern>
convert placeholders to match the output format.
--help display this list of options.
Here’s an example usage of the tool
csvtrans --sheet 1icJ0a48MIIRkbHSIbPyLNXsbTZcPKI_U80QwdX5pWf8 Resx --format resx --outputdir .\Resources
The first argument **–-sheet**
is the Google Sheet document ID followed by the Sheet Name, the next argument **–-format**
specifies the output file format, and the last argument **–-outputdir**
specifies the output folder.
You can get the Document ID from the URL of the Google Sheet
Here’s an example output
Now I can just bring these files into my project and use them directly. With the modern csproj format I don’t even need to do any changes to include these translation files, as long as the resx files are in the project folder they will be automagically included into the output. This opens up for dynamic translations at build time using your CI/CD build tools of choice
Scrollable UISegmentedControl for Xamarin.iOS
A few years ago, I had a full time job as a device developer in the Music Streaming industry. The applications we produced at the time targeted consumers and had a huge focus on UX and UI. One of the requirements our designers had was to have scrollable tabs. This was 5 years ago and before Xamarin.Forms existed so we built the iOS app and Android app separately. We used MvvmCross and the shared a lot of core code but the UI components were done per OS. When we started, the company did a recent switch to go full on with .NET on everything, so not only did we share code between apps, but we shared code across all systems within the entire organization.
Scrollable tabs come for free in Android using the built-in control TabLayout but on iOS we needed to re-create the UISegmentedControl and add scroll/pan/swipe functionality to it. On native code, you had a few options to choose from, so the first task was to find the best native implementation of it and port it to C#. A few Google searches later I found the HMSegmentedControl written by Hesham Abd-Elmegid. The component at the time was written in a single file and was a drop in replacement for the UISegmentedControl. It was functional, elegent, and directly portable to C#. It was perfect!
A few hours of focused coding later I managed to port the entire thing to C# and created a Github project for it. I originally called it HMSegmentedControl as a tribute to the author (I also sent him a thank you email at the time) but later changed it to ScrollableSegmentedControl as it was a better and more descriptive name that states exactly what it does. Recently, I re-visited this project to clean up, modernize the code, and structure of the repository. I added a README file with a useful description, screenshots, and code examples. I also published a NuGet package called ScrollableSegmentedControl to make it easier for others to use while keeping the responsibility of maintaining it.
So using the component is quite trivial. Here’s all you need to do:
Add the ScrollableSegmentedControl NuGet package
then you create an instance of ScrollableSegmentedControl and you add it to a View
using System;
using ChristianHelle.Controls.iOS;
using CoreGraphics;
using UIKit;
namespace ScrollableSegmentedControlSample
{
public partial class ViewController : UIViewController
{
public ViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
CreateScrollableSegmentedControl();
}
private void CreateScrollableSegmentedControl()
{
var sectionTitles = new[] { "One", "Two", "Three", "Four", "Five", "Six" };
View.AddSubview(new ScrollableSegmentedControl(sectionTitles)
{
Font = UIFont.FromName("STHeitiSC-Light", 18.0f),
Frame = new CGRect(0, 60, View.Frame.Width, 40),
SegmentEdgeInset = new UIEdgeInsets(0, 10, 0, 10),
SelectionStyle = ScrollableSegmentedControlSelectionStyle.FullWidthStripe,
SelectionIndicatorLocation = ScrollableSegmentedControlIndicatorLocation.Down
});
}
}
}
This would result in a segmented control that looks like this:
and can look like one of these examples depending on the SelectionStyle and SelectionIndicatorLocation
This post is probably 5 years too late but since I just only recently made it publicly available as a NuGet package I thought I should write a short article about it. I hope you find this useful
Generating a REST API Client from Visual Studio 2017 and 2019
For the past year or so, I have been doing a lot of development that involves producing an OpenAPI specification document from a .NET Core based REST API and generating client code using things like AutoRest, Swagger Codegen, OpenAPI Codegen, and NSwag. My problem with these tools is that I often need to leave Visual Studio and quite often update the tool before I can re-generate my REST API client code. After doing this a couple of times I thought that I should just build a Visual Studio extension to make my life easier. At the end of last year I started work on a Visual Studio extension called the REST API Client Code Generator, A collection of Visual Studio custom tools for generating a strongly typed REST API Client from an Open API / Swagger specification file
With this tool I can easily switch from NSwag, AutoRest, Swagger Codegen, and OpenAPI Codegen, and re-generate my code by making changes directly to the OpenAPI specification document I have in my project.
I built Visual Studio Custom Tools for each code generator so every time I make changes to the OpenAPI specification document in my project, the client code gets automatically re-generated.
You can include an NSwag Studio file in the project and right click and re-generate my client code
And a feature that I just built today, adding a dialog for adding a new OpenAPI specification document file.
This project is open source and you get browse the repository from here and download the VSIX file from the Visual Studio Marketplace