My UWP app has a resource dictionary used for localization named "Resources.resx" and now I want to add another "ResourcesXaml.resx". I want to know how to access both files like merged.
The code is below. I want to use the same Get(string key) method and access any resource in both files. Appreciate it if anyone can point out the change I need to make. Cheers!
static ResourceHandler()
{
const string selectedLanguage = "en";
Context = ResourceContext.GetForCurrentView();
var lang = new List<string> { selectedLanguage };
Context.Languages = lang;
ResourceStringMap = ResourceManager.Current.MainResourceMap.GetSubtree("Resources");
}
public static string Get(string key)
{
return ResourceStringMap.GetValue(key, Context).ValueAsString;
}
You could create two ResourceMaps and look up the key in the second one if the lookup in the first one fails, e.g.:
public static class ResourceHandler
{
private const string SelectedLanguage = "en";
private static readonly ResourceContext s_resourceContext =
new ResourceContext() { Languages = new string[1] { SelectedLanguage } };
private static readonly ResourceMap s_resourcesMap =
ResourceManager.Current.MainResourceMap.GetSubtree("Resources");
private static readonly ResourceMap s_resourcesXamlMap =
ResourceManager.Current.MainResourceMap.GetSubtree("ResourcesXaml");
public static string Get(string key)
{
string s = s_resourcesMap.GetValue(key, s_resourceContext).ValueAsString;
if (!string.IsNullOrEmpty(s))
return s;
return s_resourcesXamlMap.GetValue(key, s_resourceContext).ValueAsString;
}
}
Related
I have a .json file and a custom class.
I am taking this .json file and putting it in a dynamic variable, so that I can access specific points in the file at run time. See below code
private static dynamic elements = null;
public static dynamic Elements { get { return elements; } }
static Settings()
{
elements = JObject.Parse(Common.GetFile("Elements.json"));
}
In the below function, I am using the dynamic variable above in order to identify smaller "chunks" of the .json file. [See Below]
public void Login(string pUserName, string pPassword)
{
dynamic _module = Settings.Elements.Login;
ElementObject _userName = _module.UserName.ToObject<ElementObject>();
ElementObject _password = _module.Password.ToObject<ElementObject>();
ElementObject _loginBTN = _module.LoginButton.ToObject<ElementObject>();
_userName.OnSendKeys(pUserName);
_password.OnSendKeys(pPassword);
_loginBTN.OnClick();
}
The issue, is that ElementObject.cs has a constructor that requires the public properties to be populated via the .json script. However, when stepping through debugging, the public properties arn't getting set until after the variable declaration. [See images below]
public class ElementObject
{
public string ClassName;
public string CssSelector;
public string Id;
public string LinkText;
public string Name;
public string PartialLinkText;
public string TagName;
public string XPath;
private int index = 0;
private string finalName = "";
private string finalClassName = "";
public ElementObject()
{
var _b = new string[] { nameof(ClassName), nameof(CssSelector), nameof(Id), nameof(LinkText), nameof(Name), nameof(PartialLinkText), nameof(TagName), nameof(XPath) };
var _a = new string[] { ClassName, CssSelector, Id, LinkText, Name, PartialLinkText, TagName, XPath };
index = Array.IndexOf(_a, _a.FirstOrDefault(s => !string.IsNullOrEmpty(s)));
finalName = _a[index];
finalClassName = _b[index];
}
}
In the picture below, you can see that I am properly getting the json data.
In the below picture, by the time we get to the constructor, none of the values are being populated
In the below picture, you can see that after we stepped out of the constructor, the properties were applied, but the constructor didn't see it applied.
I created a work around, after investigation what I wanted doesn't seem to work.
Here is my work around. [See Code Below].
public ElementObject() { }
public static ElementObject Create(dynamic pSrcObj)
{
ElementObject obj = pSrcObj.ToObject<ElementObject>();
obj.Init();
return obj;
}
public void Init()
{
var _b = new string[] { nameof(ClassName), nameof(CssSelector), nameof(Id), nameof(LinkText), nameof(Name), nameof(PartialLinkText), nameof(TagName), nameof(XPath) };
var _a = new string[] { ClassName, CssSelector, Id, LinkText, Name, PartialLinkText, TagName, XPath };
index = Array.IndexOf(_a, _a.FirstOrDefault(s => !string.IsNullOrEmpty(s)));
finalName = _a[index];
finalClassName = _b[index];
}
In order for me now to create the object, i create it like this;
ElementObject _userName = ElementObject.Create(_module.UserName);
I am creating a new webhook C# function in Azure that I wish to return fixed content in different translations depending on either an incoming lang query parameter or the Accept-Language header.
For storing the different translations I naturally think of .resx files. Is there a way to utilize .resx files in Azure Function Apps?
It doesn't look like resource files are supported properly yet.
I worked around by reading the embedded resource file(s) into a resource set.
var culture = CultureInfo.CurrentUICulture;
var resourceName = $"FunctionApp.Properties.Resources.{culture.TwoLetterISOLanguageName}.resources";
var cultureResourceSet = new ResourceSet(Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName));
var localizedString = cultureResourceSet.GetString(resourceKey);
// fallback to default language if not found
Provided answer did not help me so I've done small wrapper
public static class ResourceWrapper
{
private static Dictionary<string, ResourceSet> _resourceSets = new Dictionary<string, ResourceSet>();
static ResourceWrapper()
{
_resourceSets.Add("uk", Load("uk"));
_resourceSets.Add("ru", Load("ru"));
_resourceSets.Add("en", Emails.ResourceManager.GetResourceSet(CultureInfo.InvariantCulture, false, false));
}
private static ResourceSet Load(string lang)
{
var asm = System.Reflection.Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, "bin", lang, "Function.App.resources.dll"));
var resourceName = $"Function.App.Resources.Emails.{lang}.resources";
var tt = asm.GetManifestResourceNames();
return new ResourceSet(asm.GetManifestResourceStream(resourceName));
}
public static string GetString(string key)
{
return _resourceSets[CultureInfo.CurrentUICulture.TwoLetterISOLanguageName].GetString(key);
}
}
this was my solution:
First i do this:
public void SetLanguage(FunctionRequestDTO data)
{
if (string.IsNullOrWhiteSpace(data.LanguageSetting))
{
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
}
else
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(data.LanguageSetting);
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(data.LanguageSetting);
}
ResourceWrapper.Load(Thread.CurrentThread.CurrentCulture.Name.ToLower());
}
Then:
public static class ResourceWrapper
{
private static Dictionary<string, ResourceSet> ResourceSets = new Dictionary<string, ResourceSet>();
private const string DEFAULT_LANGUAGE_VALUE = "default";
static ResourceWrapper()
{
try
{
ResourceSets.Add(DEFAULT_LANGUAGE_VALUE, new ResourceSet(Assembly.GetExecutingAssembly().GetManifestResourceStream("Function.Logic.Resources.Resource.resources")));
}
catch { }
}
public static void Load(string lang)
{
if (string.IsNullOrEmpty(lang) || ResourceSets.ContainsKey(lang))
{
return;
}
lock (new object())
{
if (ResourceSets.ContainsKey(lang))
{
return;
}
try
{
string rootPath = Environment.CurrentDirectory;
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("HOME")))
{
rootPath = Environment.GetEnvironmentVariable("HOME") + "\\site\\wwwroot\\";
}
var asm = Assembly.LoadFrom(Path.Combine(rootPath, "bin", lang, "Function.Logic.resources.dll"));
var resourceName = $"Function.Logic.Resources.Resource.{lang}.resources";
ResourceSets.Add(lang, new ResourceSet(asm.GetManifestResourceStream(resourceName)));
}
catch { }
}
}
public static string GetString(string key)
{
string value = "";
try
{
string language = System.Threading.Thread.CurrentThread.CurrentCulture.Name.ToLower();
if (string.IsNullOrEmpty(language))
{
language = DEFAULT_LANGUAGE_VALUE;
}
if (ResourceSets.ContainsKey(language))
{
value = ResourceSets[language].GetString(key);
}
}
catch { }
return value ?? "";
}
I'm trying to Path.Combine, but having highlighted string(appdatapath), helper say's that "a field initializer cannot reference the non-static field, method, or property'MySuperAPP.appdatapath' "
the code is :
string appdatapath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string path = Path.Combine(appdatapath, "second/part/of/folderpath");
what i want is:
string path = "C:/Users/USER/AppData/Local/Some/Dir/"
what i tried :
string static appdatapath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string static path = Path.Combine(appdatapath,"second/part/of/folderpath").ToString;
and
public static string GetMyLocalAppDir()
{
return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData).ToString();
}
string path = Path.Combine(GetMyLocalAppDir(),"second/part/of/folderpath").ToString;
i think the variants that i'm tried may be wrong..)
need your advice) thank's!)
When you initialize a field (this mean: when you provide a dynamic field with a value at runtime) it must be a static value.
Therefore you must declare "appdatapath" as static.
public partial class MainWindow : Window
{
private static string appdatapath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
private (static) string path = System.IO.Path.Combine(appdatapath, "second/part/of/folderpath"); //make this static if you want that this field can't be changed.
public MainWindow()
{
InitializeComponent();
}
}
Also make sure your declaration is in the right order:
public or private static or not type e.g. string name of variable
Finaly: if you have more directory's to combine, put eacht part separately:
Path.Combine(appdatapath, "second", "part", "of", "folderpath")
public static void Read_bootup3_file()
{
qq = 0;
string downloadz2;
string fileNameSDcard = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "download.txt");
string CurrentContents;
CurrentContents = fileNameSDcard;
//CurrentContents = File.ReadAllText(fileNameSDcard);
File.WriteAllText(fileNameSDcard, CurrentContents);
using (StreamReader sr = new StreamReader(fileNameSDcard))
{
downloadz2 = sr.ReadToEnd();
}
//downloadz = downloadz2.ToCharArray();
qq = 0;
for (leep = 0; leep <= lotsize; leep++)
{
for (lep = 0; lep <= 20; lep++)
{
Tester.garage_array_database[lep, leep] = downloadz[qq].ToString();
qq++;
}
}
I have to implement a solution something like - my c# function I use so many harcoded five digits codes. what I want to so is to move these hard coded values into a mapping config file(some xml) and The config will map the codes to constants that can be used in my function.
This will help to update the code value without source code re-compilation.
XML would be like:
<Codes>
<Code>
<key>code_name_1</key>
<value>value_1</value>
</Code>
...
</Codes>
OR
<Codes>
<Code key='code_name_1' value='value_1'>
<Code key='code_name_2' value='value_2'>
<Code key='code_name_3' value='value_3'>
...
</Codes>
mapping class would be:
static class codeMapping
{
const sting code1 = "code_name_1";
const sting code2 = "code_name_2";
const sting code3 = "code_name_3";
const sting code4 = "code_name_4";
...
}
function where I want to get these values:
class someClass
{
...someFunction(string someCode)
{
...
if(someCode == codeMapping.code1)
...do something
var temp2 = codeMapping.code2;
...
}
}
How to initialize constant variables of codeMapping class to the corresponding config valies? Any better design concept is also accepted.
Use static readonly fields instead and initialize it inside constructor. Hope this is what you are trying to achieve.
class Program
{
static void Main(string[] args)
{
var s = CodeMapping.Code1;
}
public static class CodeMapping
{
private static readonly string _code1;
private static readonly string _code2;
static CodeMapping()
{
string filePath = "code file path";
var doc = XElement.Load(filePath);
_code1 = doc.Elements().SingleOrDefault(r => r.Element("key").Value == "code_name_1").Element("value").Value;
_code2 = doc.Elements().SingleOrDefault(r => r.Element("key").Value == "code_name_2").Element("value").Value;
}
public static string Code1 { get { return _code1; }}
public static string Code2 { get { return _code2; } }
}
}
Static readonly vs const
I'm developing a class which contains some const strings
public static class Constants
{
public const string CarID= "car_id";
//public const string NumberID= "number_id"; // this is the second const string might be added, so
//the new created function can return the two
}
public class CarENParameters
{
public string Params { get; set; }
public CarENParameters(string carId)
{
Params = carId;
}
}
public static class CarPropertyProcess
{
//test params
public static CarENProps Parse(Uri uri,string content)
{
string carID= Regex.Matches(content, #"\$\('#CarXL'\)\.val\((\d+)\)", RegexOptions.None)[0].Groups[1].Value;
var parameters = new Dictionary<string, string>
{
{Constants.CarID, carID},
};
return new CarENProps(uri.AbsoluteUri, parameters);
}
public static CarENParameters GetParameters()
{
return new CarENParameters(Constants.CarID);
}
}
In the class Constants, I have one carID, now the case is it might have more than one const string like : public const string NumberID= "number_id";
So I want to create one function to return a list of those const strings, which are car_id and number_id with a class name CarENParameters but I havent figured out how to return a list by a get/set in a class, should I use dictionary or keyvaluespair to achieve that ? I'm quite new to C# so hope that I can have a better point of view from the helps of you guys. Thanks
Are you looking for something like this:
public static List<CarENParameters> GetParameters()
{
return new List<CarENParameters>()
{
new CarENParameters(Constants.CarID1),
new CarENParameters(Constants.CarID2),
new CarENParameters(Constants.CarID3)
}
}
You can use reflection for this
don't forget to put using System.Reflection;
// get class type
Type type = typeof(Constants);
// get a list of fields
FieldInfo[] fields = type.GetFields();
List<CarENParameters> list = new List<CarENParameters>();
// loop on field list
foreach (FieldInfo field in fields)
{
// if field is a string add it to our return list
if (field.FieldType == typeof(String))
list.Add(new CarENParameters((String) field.GetValue(null)));
}