Polib.Net, an open-source .NET Solution for managing multi-lingual apps
Hi guys, I'm back on Github for more. This time, I've been writing a simple yet powerful solution to handle translation files, the Uniforum .po style. Yes, that's right: the popular translation file format we - as developers - love even more than the .NET Framework's built-in ResourceManager. Just look at WordPress and see how folks used it there. Now the same simplicity and elegance within any of your .NET apps.
Check out my GitHub page for this new stuff: https://github.com/bigabdoul/Polib.Net. You'll love it, I promise! But for now, here's what README.md says:
What is Polib.Net?
Have you ever wanted to make multi-lingual apps but were bored with .NET's way of doing it using ResourceManager? ResourceManager is good, but one of its drawbacks is that you have to recompile (over and over again) your translations into binary files and re-deploy them whenever you add new culture-dependent bits to the app. But that's only the easy part. Managing translation files becomes a nightmare when you want to work as a team on the translations.
Instead of relying on ResourceManager, there're other ways to support multiple cultures, such as the popular PO translations file format. The PO (.po) files make it easy to support multiple languages within your applications.
The main goal of the Polib.Net Solution is to use a set of libraries to use and manage .po translation files within a .NET application in a simple yet effective way. By simple and effective, I mean that you should be able to add new translations and make them appear in your apps on the fly, just by updating your .po files, without recompiling the whole stuff into binaries and re-deploy it. Check out the "Polib.NetCore.Web" project in the demos folder, an ASP.NET Core Web application under development to showcase this feature.
Getting started
To get up and running, do the following:
$ git clone https://github.com/bigabdoul/Polib.Net.git
This action will create a subdirectory 'Polib.Net' in 'github-projects' like so: 'github-projects/Polib.net'
$ git clone https://github.com/bigabdoul/Bootstrap.Themes.git
The Polib.Net Solution does not require this project but is used in the demo web app and is a fancy way to change its appearence using many pre-built Bootstrap themes.
This should keep you going for now.
Exploring the Solution
The Solution has 4 folders, namely demos, Solution Items, src, and test.
The src folder
It contains three projects:
The test folder
One project with a couple of unit tests is available for now. I have tested only the core features of the solution. And I expect to do many more tests in the near future.
Recommended by LinkedIn
The demos folder
As previously mentioned, this folder contains the "Polib.NetCore.Web" project, which showcases an ASP.NET Core MVC web application making use of the Polib.NetStandard, Polib.NetCore.Mvc, and Bootstrap.Themes projects. For simplicity, it uses AngularJS to provide client-side functionalities, such as making Web API calls and displaying the results in the browser.
The Solution Items folder
This folder contains items without functional impact on the Solution itself, such as this README.md and other files. It just makes it easier to organize the non-vital items that are part of the Solution.
Examples
After running the demo app, let's look at how you can integrate the libraries into a new project. For example, to build a multi-lingual console app:
using Polib.Net;
using System;
// get a reference to the default translation manager instance
var manager = TranslationManager.Instance;
manager.PoFilesDirectory = "path/to/po/files";
var result = manager.TranslatePlural("fr-FR"
, "{0} media file restored from the trash."
, "{0} media files restored from the trash.", 3, 3);
Console.WriteLine(result);
Of course, you may wonder: "Where are the translation files? Do I have to write them manually?" We have good news: you can use the GNU Gettext tools to extract translatable strings from your source code (like the one above) and generate .po template files. On Windows, you can grab one of these tools from here: https://mlocati.github.io/articles/gettext-iconv-windows.html
Once downloaded and installed the binaries of gettext, you can execute the following at the command prompt (supposing that the current directory is where 'Program.cs' is):
xgettext.exe -k -kTranslatePlural:2,3 --from-code=UTF-8 -LC# --omit-header -omessages.pot Program.cs
More on that command right now! First, there's 'xgettext.exe,' a command-line tool to extract translatable strings from source code. It supports multiple programming languages, one of which is C# (hence the -LC# switch).
The -k option stands for 'keyword,' meaning the method name used to translate strings. In our case, it's the 'TranslatePlural' method, hence '-kTranslatePlural.' Then this is followed by a colon ':' and the numbers 2 (second parameter, which identifies the singular-form message) and 3 (third parameter, which identifies the plural message). The first '-k' option indicates that the xgettext program should not provide its own default keywords.
The -o (output) option followed by 'messages.pot' indicates the .pot (PO template) file to write on disk as the result of parsing our source code.
Program.cs is the name of the source code file we want to scan. We could have replaced this by a list of files specified in another file (that would be the -f option ).
The -f (file) input option indicates the file to scan. This option could be a list of files or another file that contains the list of files to scan. But here, we are using just 'Program.cs.'
This command should generate a 'messages.pot' file in the same directory as the 'Program.cs.' If you open this file with a program like "Poedit," you can effortlessly start translations. In our Main(string args[]) method above, you can rename the file's extension to .po and replace manager.PoFilesDirectory = "path/to/po/files"; with the directory name that messages.po. Or, you could load this messages.po files:
using Polib.Net.IO;
using System;
using System.Collections.Generic;
using System.IO;
namespace Polib.Net.Demos
{
class Program
{
static void Main(string[] args)
{
try
{
if (args.Length < 1)
{
Console.WriteLine("Please enter the translation file name");
return;
}
// get the file name
var filename = args[0];
if (!File.Exists(filename))
{
Console.WriteLine("File '{0}' does not exist!", filename);
return;
}
// the culture we're handling
var culture = "fr-FR";
// read the translation file; make sure to set the full path
var catalog = PoFileReader.Read(filename, culture);
// get a reference to the default translation manager instance
var manager = TranslationManager.Instance;
// add the catalog to the translation manager's catalogs dictionary;
// we could add as many different cultures as we want to support;
manager.Catalogs.Add(culture, new[] { catalog });
// use a generic list instead of an array if you intend to monitor
// changes that occur within the file system in the directory containing
// the translation files, like so:
//manager.Catalogs.Add(culture, new List<ICatalog> { catalog });
// should come as a parameter from somewhere
var filesRestored = 3;
// translate the message and format the output on the fly
var result = manager.TranslatePlural(culture
, "{0} media file restored from the trash."
, "{0} media files restored from the trash."
, filesRestored
, filesRestored);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine("The following error occured: {0}", ex);
}
}
}
}
To see how you can extract translation strings from your source code, look in the Solution Items folder for an item named 'genpot.bat.' It operates on the web app demo project by extracting translation strings from the models, views, and controllers and generating .pot files in a 'temp' directory. Should I have more time, I'll write a command-line app that does all this and more (such as merging translation strings from the source into existing .po files). The command-line app should run automatically after successfully building the demo web app.
More will be coming soon. The best way to stay current is to follow my GitHub activities: https://github.com/bigabdoul. Comments and suggestions are very appreciated, as usual.