How to programmatically add Language translation key value pair to .resx resource file in Blazor server? - localization

I want to add key value pair to GlobalResources.en-US.resx file. This is the file used by localization in my Blazor Server app.
public void Add()
{
if(!string.IsNullOrEmpty(Key) && !string.IsNullOrEmpty(Value))
{
IResourceWriter resWriter = new ResourceWriter(
#".\my_path\Resources\GlobalResources.en-US.resx");
resWriter.AddResource(Key, Value);
resWriter.Close();
}
}
I have replaced the correct path with placeholder my_path to make it shorter here.
But after executing this method, I can't view GlobalResources.en-US.resxfile in Visual studio.It says ResX file Data at the root level is invalid. Line 1, position 1. cannot be parsed. So I can't get to know whether that key, value is correctly added or not. Also localization service do not pick that value.
How can I programmatically add Language translation key value pair to this resource file in Blazor server?

Related

How to pass arbitrary data between the C module callbacks in FreeRADIUS

What is the proper/recommended method to pass data between the callbacks in a C module in FreeRADIUS?
For example, I want to create a unique request_id for the request and use it for all log entries during that request. If I create this value inside mod_authorize, how do I pass it over to mod_authenticate on the same request thread, and how do I retrieve it?
static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
// Generate uuid
uuid_t uuid;
uuid_generate_random(uuid);
// Convert to a string representation
char *request_id = talloc_array(mem_ctx, char, UUID_STR_LEN);
uuid_unparse(uuid, request_id);
// Do stuff and log authorize messages
radlog(L_INFO, "request_id inside mod_authorize: %s", request_id);
// How do I pass request_id to mod_authenticate callback
// ?????????????
return RLM_MODULE_OK;
}
static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
{
char *request_id = NULL;
// How do I retrieve the request_id value
// ???????????????????
// Do stuff and log authenticate messages
radlog(L_INFO, "request_id inside mod_authenticate: %s", request_id);
return RLM_MODULE_OK;
}
Attaching the value to the request object seems like a logical thing, but I don't see a way of doing it, other than adding a value pair to the request->reply (and I don't want to return this value to NAS).
Thank you.
Apparently, there is a range of "Temporary attributes, for local storage" (defined in the dictionary.freeradius.internal file) that can be used with one of the requests object's collections (request->config, request->reply->vps and request->packet->vps). You can find the start of this range by searching dictionary.freeradius.internal file in the FreeRADIUS repository for
ATTRIBUTE Tmp-String-0
In this case I found request->packet->vps to be appropriate, and used Tmp-String-3 to add my request_id to it while inside MOD_AUTHORIZE callback:
pair_make_request("Tmp-String-3", request_ctx->request_id, T_OP_EQ);
where pair_make_request is a macro defined as
fr_pair_make(request->packet, &request->packet->vps, _a, _b, _c)
I then retrieved it, while inside MOD_AUTHENTICATE callback:
VALUE_PAIR *vp = fr_pair_find_by_num(request->packet->vps, PW_TMP_STRING_3, 0, TAG_ANY);
The numerical values of these attributes change between the versions, you must use macro definitions instead
The macros for these attributes, such as PW_TMP_STRING_3 in the esample above, are located in the file "attributes.h" which is auto-generated during the build. Here is a quote from Arran Cudbard-Bell, that I found here:
If you really want to know where each one is used, download,
configure, build the source. Then see src/include/attributes.h for the
macro versions, and grep -r through the code. That'll at least tell
you the modules, and if you're familiar with C you should be able to
figure out how/when they're added or checked for. – Arran Cudbard-Bell
Apr 12 '15 at 20:51
In my case, the resulting file is located at /usr/include/freeradius/attributes.h
I must say that it took me unreasonable amount of effort to track this information down. There is no other trace, none whatsoever, of these attribute macros. Not in the code, not in the FreeRADIUS documentation, not in Google search results.

Localize blazor with IStringLocalizer using a unique resource file per language

I'm trying to localize my Blazor app (.NET 5.0) using IStringLocalizer and user UI selection based on cookies. Following the documentation, it seems to work if I create a .resx file for each page in my Resources/Pages folder.
I'd like to group all key-value pairs within a single file as follows :
MyApp
|-- Resources
| MyResources.resx <--- set to public modifiers to generate class!!!
| MyResources.es.resx
| MyResources.fr.resx
...
|-- Resources
| Index.razor
So in Startup.cs I register the Resources folder:
services.AddControllers();
services.AddLocalization(options => options.ResourcesPath = "Resources");
I also added MapControllers in the configure method, as well as registering supported cultures. I also added the controller:
[Route("[controller]/[action]")]
public class CultureController : Controller {
public IActionResult SetCulture(string culture, string redirectUri) {
if (culture != null) {
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)));
}
return LocalRedirect(redirectUri);
}
}
Now, on my main "index.razor" page I inject the IStringLocalizer<MyResources> as follows:
#page "/index"
#inject IStringLocalizer<Language> _localizer
<h2>#_localizer["hello_world"]</h2>
<h2>#DateTime.Now.ToShortDateString()</h2>
<h2>#DateTime.Now.ToLongDateString()</h2>
I make sure that all resx files actually contain the "hello_world" key with some values and added a language selector.
When I run the app, changing the language does change the displayed dates, however, the hello_world key is not found so the app displays the key instead. When exploring the _localizer variable, I see that the container is empty - none of the key-value pairs of the .resx are actually loaded.
Is it possible to get this to work? If so, what am I doing wrong here?
The mistake is because of naming here:
#inject IStringLocalizer<Language> _localizer
should be
#inject IStringLocalizer<MyResources> _localizer
And important is to add an empty file MyResources.razor at the root of the project.
Edit:
Another mistake I made is to add the myApp.Resources to _Imports.razor
...
#using myApp.Resources <==== do NOT add this
#neggenbe
Adding an empty razor(AppLang.razor) component at the root of my project with same name with my resource(AppLang.resx) file solved the challenge. I stumbled accross #neggenbe after over 48 hours trying to figure out what was wrong with my code.
If your project is purely blazor, you wont come accross this challenge but if its a mix of MVC and razor(blazor) components, then you'll definately need to do this.

How can I write FlowFile attributes to Avro metadata inside the FlowFile's content?

I am creating FlowFiles that are manipulated and split downstream after being emitted by an ExecuteSql processor. I have populated the FlowFiles' attributes with data that I want to put into the Avro metadata contained within each FlowFile's content.
How can I do this?
I've tried using an UpdateRecord processor configured with an AvroReader and AvroRecordSetWriter and a property with a key of /canary that should be writing a FlowFile attribute to that key somewhere in the Avro document. It does not appear anywhere in the output, though.
It would be acceptable to move the records in the Avro data to a subkey and have a metadata section be a part of the record data. I would prefer not to do this, though, because it does not seem like the correct solution and because it sounds much more complex than simply modifying the Avro metadata.
The record-aware processors (and the Readers/Writers) are not metadata-aware, meaning they cannot currently (as of NiFi 1.5.0) act on metadata in any way (inspect, create, delete, etc.), so UpdateRecord won't work for metadata per se. With your /canary property key, it will try to insert a field into your Avro record at the top level, named canary, and should have the value you specify. However I believe your output schema needs to have the canary field added at the top level, or it may be ignored (I'm not positive of this, you can check the output schema to see if it is added automatically).
There is currently no NiFi processor that can update Avro metadata explicitly (MergeContent does some with regards to merging various Avro files together, but you can't choose to set a value, e.g.). However I have an unpolished Groovy script you could use in ExecuteScript to add metadata to Avro files in NiFi 1.5.0+. In ExecuteScript you would set the language to Groovy and the following as the Script Body, then add user-defined (aka "dynamic" properties) to ExecuteScript, where the key will be the metadata key, and the evaluated value (the properties support Expression Language) will be the value:
#Grab('org.apache.avro:avro:1.8.1')
import org.apache.avro.*
import org.apache.avro.file.*
import org.apache.avro.generic.*
def flowFile = session.get()
if(!flowFile) return
try {
// Save off dynamic property values for metadata key/values later
def metadata = [:]
context.properties.findAll {e -> e.key.dynamic}.each {k,v -> metadata.put(k.name, context.getProperty(k).evaluateAttributeExpressions(flowFile).value.bytes)}
flowFile = session.write(flowFile, {inStream, outStream ->
DataFileStream<GenericRecord> reader = new DataFileStream<>(inStream, new GenericDatumReader<GenericRecord>())
DataFileWriter<GenericRecord> writer = new DataFileWriter<>(new GenericDatumWriter<GenericRecord>())
def schema = reader.schema
def inputCodec = reader.getMetaString(DataFileConstants.CODEC) ?: DataFileConstants.NULL_CODEC
// Forward the existing metadata to the output
reader.metaKeys.each { key ->
if (!DataFileWriter.isReservedMeta(key)) {
byte[] metadatum = reader.getMeta(key)
writer.setMeta(key, metadatum)
}
}
// For each dynamic property, set the key/value pair as Avro metadata
metadata.each {k,v -> writer.setMeta(k,v)}
writer.setCodec(CodecFactory.fromString(inputCodec))
writer.create(schema, outStream)
writer.appendAllFrom(reader, false)
} as StreamCallback)
session.transfer(flowFile, REL_SUCCESS)
} catch(e) {
log.error('Error adding Avro metadata, penalizing flow file and routing to failure', e)
flowFile = session.penalize(flowFile)
session.transfer(flowFile, REL_FAILURE)
}
Note that this script can work with versions of NiFi previous to 1.5.0, but the #Grab at the top is not supported until 1.5.0, so you'd have to download Avro and its dependencies into a flat folder, and point to that in the Module Directory property of ExecuteScript.

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");
}
}
}

Is there an easy way to view the contents of a FormCollection?

When testing/debugging an ASP.NET MVC application, it's common to submit a form and then check all of the name/value pairs to make sure
All of the expected keys are present
All of the expected keys have the expected values
Debugging in Visual Studio is great for checking if a single variable (or even a simple object) contains the expected value(s), and as far as a FormCollection, it's pretty easy to check the presence of the keys. However, checking the key/value pairings in a FormCollection is a huge hassle. Is there a simple way to get Visual Studio to list the keys and their values side-by-side for a quick check?
Just a quick custom check
public void Edit(FormCollection team)
{
System.Text.StringBuilder st = new System.Text.StringBuilder();
foreach (string key in team.Keys)
{
st.AppendLine(String.Format("{0} - {1}", key, team.GetValue(key).AttemptedValue));
}
string formValues = st.ToString();
//Response.Write(st.ToString());
}
You can then place your mouse on formValues to check the key-value. Clicking the magnifier would reveal the Key-Values
Take a look at Glimpse, it is on nuGet. It exposes lots of information and is invaluable with AJAX and MVC development.
At its core Glimpse allows you to debug your web site or web service right in the browser. Glimpse allows you to "Glimpse" into what's going on in your web server. In other words what Firebug is to debugging your client side code, Glimpse is to debugging your server within the client.
Here is a method that outputs the collection to the Immediate window in a readable key/value pair format, one pair per line of output:
private void DebugWriteFormCollection(FormCollection collection)
{
foreach (string key in collection.Keys)
{
string value = collection.GetValue(key).AttemptedValue;
string output = string.Format("{0}: {1}", key, value);
System.Diagnostics.Debug.WriteLine(output);
}
}
Add that to your code and set a breakpoint. When you hit the breakpoint, call the method from the Immediate window:
DebugWriteFormCollection(collection);
Result:
Key1: Value1
Key2: Value2
Key3: Value3
etc.

Resources