Wrong language codes generated by Windows.Globalization.ApplicationLanguages.ManifestLanguages - localization

I am localizing my UWP app in several languages using the Multilingual App Toolkit
here are some screen shots of how the MultilingualResourcesFolder and the Strings folder looks like in the project
Multilingual Resources
Strings
All the files are filled with the correct values.
In the application I retrieve the list of available languages with
Windows.Globalization.ApplicationLanguages.ManifestLanguages and iterate through them. The iteration yields these results
pt-PT
ro-RO
ru
sk
sl
This is very strange because the languages are declared in exaclty the same way but for some languages the language code includes the locale and for some it doesn't , for no reason I can undestand.
In the way I declare them the iteration should yield
pt-PT
ro-RO
ru-RU
sk-SK
sl-SL
I have tried manually declaring the languages in the appxmanifest by replacing x-generate like this
<Resources>
<Resource Language="ru-ru"/>
<Resource Language="sk-sk"/>
<Resource Language="pt-pt"/>
<Resource Language="sk-sk"/>
<Resource Language="sl-sl"/>
</Resources
but the results are the same.
I need to get the application to recognize the locale as well as the language for every language.
Can anybody help?

Ok, I've got a solution for you. There's also a separate issue that you're dealing with, which is why x-generate in the manifest isn't doing the right thing (or is it?). I'm investigating that on the side.
So, this is the method you want:
public static string GetLocaleFromLanguage(string identifier)
{
int result;
StringBuilder localeName = new StringBuilder(500);
result = LocaleFunctions.ResolveLocaleName(identifier, localeName, 500);
StringBuilder localeDisplay = new StringBuilder(500);
result = LocaleFunctions.GetLocaleInfoEx(localeName.ToString(), LCTYPE.LOCALE_SENGLISHDISPLAYNAME, localeDisplay, 500);
return localeDisplay.ToString();
}
And of course, you're going to need the externs:
class LocaleFunctions
{
// pInvoke declarations
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int GetLocaleInfoEx(String lpLocaleName, LCTYPE LCType, StringBuilder lpLCData, int cchData);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int ResolveLocaleName(string lpNameToResolve, StringBuilder lpLocaleName, int cchLocaleName);
}
Unfortunately, you're also going to need the declaration for LCTYPE. The code for that can be found at this link: http://www.pinvoke.net/default.aspx/Enums/LCTYPE.html
(It's a massive chunk of code and I don't want to just copy that here.
In my code, I manually added the following language resources to my manifest (again, I'm not sure why x-generate isn't adding the Russian locales here, but this works around it):
<Resources>
<Resource Language="EN-US" />
<Resource Language="ES-ES" />
<Resource Language="ES-MX" />
<Resource Language="PT-PT" />
<Resource Language="RO-RO" />
<Resource Language="RU-RU" />
<Resource Language="RU-UA" />
</Resources>
And this is the method I'm using to call in:
private void button_Click(object sender, RoutedEventArgs e)
{
string output = "";
foreach (string thisManifestLanguage in Windows.Globalization.ApplicationLanguages.ManifestLanguages)
{
output += thisManifestLanguage + ": ";
string ResolvedName = LocalizationTesting.LocaleTest.GetLocaleFromLanguage(thisManifestLanguage);
output += ResolvedName + "\n";
}
this.outputText.Text = output;
}
When I called this, the output I got was:
en-US: English (United States)
es-ES: Spanish (Spain, International Sort)
es-MX: Spanish (Mexico)
pt-PT: Portuguese (Portugal)
ro-RO: Romanian (Romania)
ru: Russian (Russia)
ru-UA: Russian (Ukraine)
I should point out that in GetLocaleFromLanguage, localeName for "ru" gets "ru-RU", so if that's what you're looking for, that's available too.
Let me know if this doesn't meet with your needs. I'll see if I can get a reason about why in my case, I had to explicitly add ru-UA to my manifest.

I'll let Dante follow up, but I'm curious why this list is interesting? Eg: What's the user scenario?
A UWP lists the languages it can provide data for, and the Region & Language Settings collects a list of languages that the user understands. So then Windows figures out which language best matches the user and app language and the resource loader uses that. So I'm curious what scenario is missing?

Related

F# reading custom configuration and representing it as ConfigurationSection with ConfigurationElements

I am rather new to F# but I have a question about creating and reading custom configuration file. I know how it would look in c# so for example I have a simple config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="customSection" type="Tool.Lib.Config, Tool.Lib" />
</configSections>
<communicationSection>
<responseTimeoutInMs value="900000" />
</communicationSection>
</configuration>
Basing on that in c# it is simple. I am creating model named Config with properties marked as ConfigurationProperty (witch relates to xml node name, in this case responseTimeoutInMs) something like:
[ConfigurationProperty("responseTimeoutInMs")]
public ResponseTimeoutConfigElement ResponseTimeoutInMs
{
get => (ResponseTimeoutConfigElement)base["responseTimeoutInMs"];
set => base["responseTimeoutInMs"] = value;
}
And of course value is set as ConfigurationElement so:
public class ResponseTimeoutConfigElement : ConfigurationElement
{
[ConfigurationProperty("value", IsRequired = true, IsKey = true, DefaultValue = 0)]
public int Value => (int)base["value"];
}
It is a nice mechanism, I can pin converters into it and create types I need while reading configuration.
I know i can read default config using ConfigurationManager and exe configuration map, but this is basic config reading using key and value.
So my question is, is there something similar in F# to this in C#?
I'm not sure if it's quite what you're after as you mention using a "custom configuration file", but in the past I've used the AppSettings Type Provider to get strongly typed access to app variables.
If that's not appropriate, there's also a more standard XML type provider that might help?
I find type providers really useful in avoiding having to write boilerplate code for simple access, and they're a really nice feature of F# development.
You can do pretty much the same thing in F# as in C#:
type ResponseTimeoutConfigElement() =
inherit ConfigurationElement()
[<ConfigurationProperty("value", IsRequired = true, IsKey = true, DefaultValue = 0)>]
member this.Value = base.["value"] :?> int
type Config() =
inherit ConfigurationSection()
[<ConfigurationProperty("responseTimeoutInMs")>]
member this.ResponseTimeInMs
with get() = base.["responseTimeoutInMs"] :?> ResponseTimeoutConfigElement
and set (value: ResponseTimeoutConfigElement) = base.["responseTimeoutInMs"] <- value

External files with locale messages with a page in tapestry 5

We are using Tapestry 5.4-beta-4. My problem is:
I need to keep files with locale data in an external location and under different file name then tapestry usual app.properties or pageName_locale.properties. Those files pool messages that should be then used on all pages as required (so no tapestry usual one_page-one_message_file). The files are retrieved and loaded into tapestry during application startup. Currently i am doing it like this:
#Contribute(ComponentMessagesSource.class)
public void contributeComponentMessagesSource(OrderedConfiguration<Resource> configuration, List<String> localeFiles, List<String> languages) {
for(String language: languages){
for(String fileName : localeFiles){
String localeFileName = fileName + "_" + language + ".properties";
Resource resource = new Resource(localeFileName );
configuration.add(localeFileName, resource, "before:AppCatalog");
}
}
}
The above code works in that the message object injected into pages is populated with all the messages. Unfortunatly these are only the messages that are in the default ( first on the tapestry.supported-locales list) locale. This never changes.
We want the locale to be set to the browser locale, send to the service in the header. This works for those messages passed to tapestry in the traditional way (through app.properties) but not for those set in the above code. Actually, if the browser language changes, the Messages object changes too but only those keys that were in the app.properties are assigned new values. Keys that were from external files always have the default values.
My guess is that tapestry doesn't know which keys from Messages object it should refresh (the keys from external files ale not beeing linked to any page).
Is there some way that this could be solved with us keeping the current file structure?
I think the problem is that you add the language (locale) to the file name that you contribute to ComponentMessagesSource.
For example if you contribute
example_de.properties
Tapestry tries to load
example_de_<locale>.properties
If that file does not exist, it will fall back to the original file (i.e. example_de.properties).
Instead you should contribute
example.properties
and Tapestry will add the language to the file name automatically (see MessagesSourceImpl.findBundleProperties() for actual implementation).
#Contribute(ComponentMessagesSource.class)
public void contributeComponentMessagesSource(OrderedConfiguration<Resource> configuration, List<String> localeFiles, List<String> languages) {
for(String language: languages){
for(String fileName : localeFiles){
String localeFileName = fileName + ".properties";
Resource resource = new Resource(localeFileName );
configuration.add(localeFileName, resource, "before:AppCatalog");
}
}
}

How to localize p:captcha

I would like to create a localization for PrimeFaces <p:captcha> component. I know how to localize validation error messages by using requiredMessage or validatorMessage attributes as follows:
<p:captcha label="Captcha" theme="clean" requiredMessage="#{msg['primefaces.captcha.INVALID']}" validatorMessage="#{msg['primefaces.tree.REQUIRED']}"/>
The problem is that I don't know how to localize e.g. labels (as depicted below)
So I need to localize points 1) and 2) and tooltips which are showed when user hovers any of buttons. It would be also nice if reCaptcha could use some kind of localized dictionary (3rd point) but I doubt that it's possible and it's really optional. I know that reCaptcha has few supported languages but mine (pl - polish) is unfortunately not supported...
Just add a language attribute to the captcha tag
<p:captcha language="pl" />
If you have a session bean that stores the user language you can use that too, for example:
<p:captcha language="#{userSessionBean.locale}" />
The bean:
#ManagedBean
#SessionScoped
public class UserSessionBean {
private Locale locale;
public Locale getLocale(){ return locale; }
public void setLocale(Locale locale) { this.locale = locale; }
}

Flash, Ant and lots of regular expression replaces

I have a flash project which, for optimization purposes, has to have constant references replaced with literals during release build.
There are hundreds of constants which I want to replace. All of them are stored in single file, in this format:
FILE: Constants.as
public static const CONST_1 :uint = 0;
public static const CONST_LOLO :int = -1;
public static const CONST_WHEE :Number = 2.55;
public static const OTHER_CONST :String = "La string!";
public static const ITSAMEMARIO :String = "O, HAI!";
public static const MAGE_WALL :uint = 15;
I figure I could do it manually, like that:
<replaceregexp match="CONST_1" replace="0">
<fileset dir="${project.sourcePath}" includes="**/*.as" />
</replaceregexp>
<replaceregexp match="CONST_LOLO" replace="-1">
<fileset dir="${project.sourcePath}" includes="**/*.as" />
</replaceregexp>
And so on, for all the other variables. The problem is twofold - first of all, it is quite a lot of work. But the bigger problem is, that these constants can change and I'd have to remember to do the change in two places.
Generally I am using Ant (which I just started to learn too) to accomplish this task, but if you think there is a better way, I am all ears. There are two solutions I can think of, none of which I know how to execute:
Write some smarty-pants piece of Ant code which would parse this constants file and happily do the replaces keeping everything in memory.
Make the task first parse the Constants.as, output a new Ant script, which then will be executed by the first task.
I am using Flash Builder 4.5 for all my Ant needs.
EDIT:
Some clarification. In the project I am using Constants, for example LEVEL_WIDTH. All of these constants are declared in the aforementioned Constants.as. Now what I want is to replace all of the instances of these constants in the whole project with their actual value. So such line:
return (x >= 0 && x < Constants.LEVEL_WIDTH);
will be replaced by:
return (x >= 0 && x < 20);
OK this is not the easiest thing to do with ant. First you need to know what you can change. This means all the names of your constants as well as the corresponding values. Are the constant names unique? If yes this sounds like a map structure to me. Then you need to regexreplace all your source files which contain one or more of these variables so that every constant is replaced with the actual value. This is not what ant is designed for but you can do it with a script def.
I would do this with java like this :
Store all constant/values into a map (if the constants are unique) else use a different structure.
Sample code :
<project name="test" default="build">
<property name="constants" value="constants.txt"/>
<scriptdef name="replaceConstants" language="java">
<attribute name="constants" />
<attribute name="srcFile" />
<![CDATA[
import java.util.*;
import java.util.regex.*;
ArrayList constantNameList = new ArrayList();
ArrayList constantValueList = new ArrayList();
var constantFile = attributes.get("constants");
Pattern regex = Pattern.compile("(?<=const)\\s+(\\b\\w+\\b).*?=\\s*(.*?)\\s*;");
Matcher regexMatcher = regex.matcher(constantFile);
while (regexMatcher.find()) {
constantNameList.add(regexMatcher.group(1));
constantValueList.add(regexMatcher.group(2));
}
for(int i = 0; i < constantNameList.size(); ++i)
{
//debugging
System.out.print("key : ");
System.out.print(constantNameList.get(i));
System.out.print(" value : ");
System.out.println(constantValueList.get(i));
//do the actual replacement here
}
]]>
</scriptdef>
<target name="build">
<loadfile property="constants.file" srcFile="${constants}"/>
<loadfile property="source.file" srcFile="sourceFile.txt"/>
<echo message="${constants.file}"/>
<replaceConstants constants="${constants.file}" srcFile="${source.file}"/>
</target>
</project>
You will need java 1.6 or later to run this as well as http://www.java2s.com/Code/Jar/ABC/bsh-2.0b5.jar.htm
This jar to run it.
Output :
[replaceConstants] key : CONST_1 value : 0
[replaceConstants] key : CONST_LOLO value : -1
[replaceConstants] key : CONST_WHEE value : 2.55
[replaceConstants] key : OTHER_CONST value : "La string!"
[replaceConstants] key : ITSAMEMARIO value : "O, HAI!"
[replaceConstants] key : MAGE_WALL value : 15
So what I did is stored all the constant names/value into two arrays. You need to iterate through the arrays and regex replace for each of your source files. The whole thing can be a macrodef which you can call multiple times.

asp.net MVC: localization

I have my target language in Session["lang"], which is either "en" or "it". I have added this to the Site.master:
<script runat="server">
void Page_Load(object sender, EventArgs e) {
string lang = Session["lang"].ToString();
System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture(lang);
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Globalization.CultureInfo.CreateSpecificCulture(lang);
}
</script>
Then I'd like to invoke a resource string like this:
<asp:Label ID="Label1" runat="server" Text="<%$ Resources:Global, test %>"></asp:Label>
I have two files in the App_GlobalResources, named Global.resx and Global.en.resx.
The problems is that no matter what is in the lang variable, I always get the results from the main Global.resx, and I never get the english version from Global.en.resx
I am doing this wrong entirely??
I tried putting the System.Threading... part in the Application_PreRequestHandlerExecute method in Global.asax.cs but the result was the same.
Thanks
PS: I am asking about a way to make this work in a simple way. If I was to use the complicate way, I'd go with this: http://helios.ca/2009/05/27/aspnet-mvc-and-localization/
i had the same dilema(how to implement localization) in my asp.net mvc app.
I followed the instructions posted here and it works like a charm.
So i created a folder named Localization under Content and then i create Resources resx files for each language i want to translate. Keep in mind that there is a convention for the resx file names. ie
Resources.resx is the default fall back for everything.
Resources.en-GB.resx is for english GB
Resources.en-US.resx is for english US
etc.
Just make sure you follow the instructions posted in the link to embed and make the Resources available in all places in your app (views, controllers etc)
Edit:
I want to add that i ommited this line from web.config since i wanted to manually set the local from my app.
<globalization uiCulture="auto" culture="auto"/>
Instead i have created the following class:
public class SmartController : Controller
{
public SmartController()
{
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
}
}
All controllers inherit from this class.
Since this is an administrative set of the locale i have to set it from my apps settings. You could read it from Cookies and set it, or otherwise. This is imo the simplest solution for localization that i have encountered so far.
Once implemented you can refer to any string you add by the following simple line of code, no extra code needed.
<%= Resources.Strings.TranslatedTerm %>
I bet this one is a duplicate.
Anyway - all you need is here (assuming that you are using webforms viewengine (might work with others too, haven't investigated)).
Oh well... here goes my 'summary':
Helpers are just a part. You need to do some modifications with your default view engine too . On createview/createpartialview it should return localizationwebformview which adds a path key to viewdata which is used by htmlhelper to find resourceexpressionsfields and pass them to localizationhelpers class which retrieves desired value.
Little bonus=>
This might be handy if you don't want to recreate resource folders for view subfolders
(in case you modify viewengine.view/partialviewlocationformats):
private static string ReformatVirtualPath(string virtualPath)
{
//This allows NOT to duplicate App_localResources directory
// ~/Views/Shared/Partial/Some/BulltihS/_View.ascx
// turns into =>
// ~/Views/Shared/_View.ascx
var start = #"(~(/?\w*/?){2})";
var end = #"(\w*.as(c|p)x)";
start = Regex.Match(virtualPath, start).Value;
end = Regex.Match(virtualPath, end).Value;
return start + end;
}
usage:
internal static ResourceExpressionFields GetResourceFields
(string expression, string virtualPath)
{
virtualPath = ReformatVirtualPath(virtualPath);
var context = new ExpressionBuilderContext(virtualPath);
var builder = new ResourceExpressionBuilder();
return (ResourceExpressionFields)
builder.ParseExpression(expression, typeof(string), context);
}
EDIT:
but it might be a good idea to avoid App_GlobalResources and App_LocalResources as K. Scott Allen suggests (check Konstantinos answer).

Resources