How to include a .properties file in i18n.properties file on SAPUI5? - internationalization

Environement
Framework: SAPUI5 V1.38.39
Issue
Well, the issue may semble stupid but is it as follow :
I have an application with a lot of text, which makes very huge i18n files, that why I wanted to separate them into several files for the files to be cleaner. For example :
an i18n.properties including i18n_food.properties, i18n_ingredient.properties, etc.
an i18n_en.properties including i18n_food_en.properties, i18n_ingredient_en.properties, etc.
an i18n_de.properties including i18n_food_de.properties, i18n_ingredient_de.properties, etc.
an i18n_fr.properties including i18n_food_fr.properties, i18n_ingredient_fr.properties, etc.
Attemps
What I try is to make as for Apache .properties files meaning :
#i18n.properties
include = i18n_food.properties
#i18n_food.properties
recipeSelection = A selection of recipe
recipeDetail = Recipe details
But it doesn't work, in the view, I bind with "{i18n>recipeDetail}" and instead of showing "Recipe details" it shows "recipeDetail"

Check you manifest file, whether you have updated your new i18n file name
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "xxxx.xxxx.i18n.i18n",
"bundleName": "xxxx.xxxx.i18n.i18n_food"
}
}
}

Related

How to develop Custom Action on Bot Framework v2.0

Could someone please help with how to enable / develop custom action with latest preview / 2.0 version of Bot Framweork. The microsoft documentation only seems to work for v1.4.1
Thanks
So, BotComponents are the new route for custom actions. Please follow the directions here. The two things you will likely have to change are:
Update/add a newer package for Microsoft.Azure.KeyVault.Core. I went with 3.0.5 for both projects.
Use "components":[{"name":"MultiplyDialog"}] instead of "components":[{"name":"CustomAction.MultiplyDialog"}].
On point #2, I was getting a build error (FileNotFoundException: Could not load file or assembly 'CustomAction.MultiplyDialog) and thefore did the above to resolve. Odd thing here is that once I was able to build in VS, then run and test in Composer, it's once again back to CustomAction.MultiplyDialog, but it works.
This documenation should make it's way to the Composer documentation once 2.0 is released.
Please find the documentation here.
Add a new project named MultiplyDialog to your solution. In Visual
Studio right-click on the solution in the Solution Explorer and
select Add > New Project. Use the Class Library project template.
Add a reference to the Microsoft.Bot.Builder.Adaptive.Runtime
package. Use the same version as the bot depends on.
Add a project reference from the bot project to the component
project. Right-click on the project and select Add > Project
Reference. Choose the MultiplyDialog project and click OK.
Build the entire solution to restore all packages and validate the
dependency tree.
Create the custom action
Actions in Composer are special implementations of the Dialog base class. This allows each action in the trigger to be pushed onto the dialog stack, and executed in turn.
In the new project, rename the Class1.cs file to MultiplyDialog.cs, and update it's contents to look like the below:
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using AdaptiveExpressions.Properties;
using Microsoft.Bot.Builder.Dialogs;
using Newtonsoft.Json;
public class MultiplyDialog : Dialog
{
[JsonConstructor]
public MultiplyDialog([CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
: base()
{
// enable instances of this command as debug break point
RegisterSourceLocation(sourceFilePath, sourceLineNumber);
}
[JsonProperty("$kind")]
public const string Kind = "MultiplyDialog";
[JsonProperty("arg1")]
public NumberExpression Arg1 { get; set; }
[JsonProperty("arg2")]
public NumberExpression Arg2 { get; set; }
[JsonProperty("resultProperty")]
public StringExpression ResultProperty { get; set; }
public override Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
{
var arg1 = Arg1.GetValue(dc.State);
var arg2 = Arg2.GetValue(dc.State);
var result = Convert.ToInt32(arg1) * Convert.ToInt32(arg2);
if (this.ResultProperty != null)
{
dc.State.SetValue(this.ResultProperty.GetValue(dc.State), result);
}
return dc.EndDialogAsync(result: result, cancellationToken: cancellationToken);
}
}
Create the schema file
The .schema file for the component is a partial schema that will be merged into the main .schema file for the bot. Although it is possible to edit the main sdk.schema file for the bot directly, doing so is not recommended. Merging partial schema files will isolate changes, allow for easier recovery from errors, and enable easier packaging of your component for reuse.
Create a new file in the project named MultiplyDialog.schema and update the contents to the below:
{
"$schema": "https://schemas.botframework.com/schemas/component/v1.0/component.schema",
"$role": "implements(Microsoft.IDialog)",
"title": "Multiply",
"description": "This will return the result of arg1*arg2",
"type": "object",
"additionalProperties": false,
"properties": {
"arg1": {
"$ref": "schema:#/definitions/integerExpression",
"title": "Arg1",
"description": "Value from callers memory to use as arg 1"
},
"arg2": {
"$ref": "schema:#/definitions/integerExpression",
"title": "Arg2",
"description": "Value from callers memory to use as arg 2"
},
"resultProperty": {
"$ref": "schema:#/definitions/stringExpression",
"title": "Result",
"description": "Value from callers memory to store the result"
}
}
}
Create the BotComponent class
The adaptive runtime will dynamically discover and inject components at startup time.
Create a new MultiplyDialogBotComponent.cs file in the project and update the contents to
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
public class MultiplyDialogBotComponent : BotComponent
{
public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
// Anything that could be done in Startup.ConfigureServices can be done here.
// In this case, the MultiplyDialog needs to be added as a new DeclarativeType.
services.AddSingleton<DeclarativeType>(sp => new DeclarativeType<MultiplyDialog>(MultiplyDialog.Kind));
}
}
In the appsettings.json file of the bot project (located at \settings)to include the MultiplyDialogBotComponent in the runtimeSettings/components array.
"runtimeSettings": {
"components": [
{
"name": "MultiplyDialog"
}
]
}
Merge schema files
The final step is to merge the partial schema file from the MultiplyDialog project into the main sdk.schema file for the bot. This makes the custom action available for use in Composer.
Navigate to the schemas folder in the myBot project. This folder contains a PowerShell script and a bash script. Use an elevated PowerShell terminal to execute the PowerShell script. You will need to either copy/paste the contents of the script, or ensure your execution-policy allows for running unsigned scripts.
To validate the script executed successfully, search for MultiplyDialog inside the MyBot\schemas\sdk.schema file and validate that the partial schema from the MultiplyDialog.schema file is included in sdk.schema.

How to nest interfaces using File Nesting in ASP.Net Core

I want to use Microsoft's custom file nesting option in Visual Studio to nest implementation class files with their "parent" interfaces, so in this example, I would like ReportRepository.cs to appear nested under IReportRepository.cs in the solution explorer. The same should be for all repositories.
I have created the .filenesting.json file in the root of the solution, but I have no idea how to use it and documentation is very sparse.
Does anyone know how I can achieve this in Visual Studio 2019?
As far as I can gather it is not possible to group by prefixes. You can only group by extensions or suffixes, or entire file names.
This means you can't define a rule for this. However there are 2 options:
Define a rule for each file
Change your naming scheme
Defining a rule for each file
To define a rule for each file you would use the fileToFile provider.
This would look like so:
{
"help": "https://go.microsoft.com/fwlink/?linkid=866610",
"root": true,
"dependentFileProviders": {
"add": {
"fileToFile": {
"add": {
"IInvestigationRepository.cs": [ // Parent file
"InvestigationRepository.cs" // Nested file
],
"IReporterRepository.cs": [ // Parent file
"ReporterRepository.cs" // Nested file
]
...
}
}
}
}
}
Using a different naming scheme
Alternatively, if the first option is not to your liking, you could use a different naming scheme for your files, and let the classes keep their old names.
Then you could use the fileSuffixToExtension provider like such:
{
"help": "https://go.microsoft.com/fwlink/?linkid=866610",
"root": true,
"dependentFileProviders": {
"add": {
"pathSegment": {
"add": {
".DefaultImplementation.cs": [
".cs"
]
}
}
}
}
}
This would map
IInvestigationRepository.DefaultImplementation.csto IInvestigationRepository.cs,
IReporterRepository.DefaultImplementation.csto IReporterRepository.cs
and so on.
This would also make the purpose of your files clearer, as just having the same name doesn't tell you what it's doing with the Interface, just that is has something to do with it.
If you don't want to use a notation with . and would prefer to use -, you can do that by replacing "pathSegment" with "fileSuffixToExtension", and replacing ".DefaultImplementation.cs" with "-DefaultImplementation.cs"
We use the following pattern in our .csproj files to auto nest concretes with their interfaces (if they reside in the same directory).
<ItemGroup>
<Compile Update="**\*.cs">
<DependentUpon>$([System.String]::Copy(I%(Filename).cs))</DependentUpon>
</Compile>
</ItemGroup>
I know that the question was to use the custom nesting options in Visual Studio; however, until Microsoft adds prefix functionality, this method does the trick.

EventFlow - Creating a Custom Filter to attach Source Server Information

I'm assuming this is a pretty common question, how do we easily add Server info to an EventFlow event?
My scenario is that I'm deploying an application that will have its own environment specific EventFlowConfig.json, but each server in the farm will get that same json file. So... how can I tell which server in the farm sent the event to ElasticSearch?
One option is to use .net to get servername and send it as a column, which would require that I add server name to every event. That seems a little excessive but it would do the job. I was hoping there was an easier way besides having to actually code this into an event.
Thanks for your time,
Greg
Edit 4 - Karol has been great helping me get this working example up and running, THANK YOU KAROL!!! Attempting to add create a custom filter as an extension:
We need to create a new class for the custom Filter Factory
We then need to create a second new class and have it implement the IFilter interface. To pass the health monitor from the factory we used a constructor.
Use the Evaluate function as our area to add the data (eventData.AddPayloadProperty)
Then refer to the custom filter in the extensions area of our EventFlowConfig.json.
a. The category is filterFactory
b. The type is the name of your class.
c. The qualified type name is in the "type-name, assembly-name”. For example (assuming you name your filter factory ‘MyCustomFilterFactory’): “My.Application.Logging.MyCustomFilterFactory, My.Application.Assembly.WhereCustomFilterAndItsFactoreLive”
Add a reference to Microsoft.Extensions.Configuration where the C# code lives.
Then you can reference your custom filter anywhere you need to, here we are using a global filter
Working example:
class CustomGlobalFilter : IFilter
{
private IHealthReporter HealthReporter;
private string MachineName;
public CustomGlobalFilter(string ServerName, IHealthReporter HealthReporter)
{
MachineName = ServerName;
this.HealthReporter = HealthReporter;
}
FilterResult IFilter.Evaluate(EventData eventData)
{
eventData.AddPayloadProperty("ServerName", MachineName, HealthReporter, "CustomGlobalFilter");
return FilterResult.KeepEvent;
}
}
class CustomGlobalFilterFactory : IPipelineItemFactory<CustomGlobalFilter>
{
public CustomGlobalFilter CreateItem(IConfiguration configuration, IHealthReporter healthReporter)
{
CustomGlobalFilter GlobalFilter = new CustomGlobalFilter(System.Environment.MachineName, healthReporter);
return GlobalFilter;
}
}
Then in the EventFlow Config:
"filters": [
{
"type": "drop",
"include": "Level == Verbose"
},
{
"type": "CustomGlobalFilter"
}
],
...
"extensions": [
{
"category": "filterFactory",
"type": "CustomGlobalFilter",
"qualifiedTypeName": "My.Company.Presentation.App.CustomGlobalFilter, My.Company.Presentation.App"
}
It is not something that is built into EventFlow today, but there are at least a couple of options:
Use EventFlow extensibility to add a custom filter that adds these properties to every event it “sees”.
In many logging libraries there is a concept of “initializers” or “enrichment” that can be used to automatically add contextual properties. For example in Serilog (which is natively supported by EventFlow)

how to re-use a language file in multiple languages without doubling of files with Titanium

So I'm using a language file in Titanium to serve TSS properties I want to re-use throughout the entire app at different locations. These language file variables should be used in the themes folder (or any other TSS file for that matter).
Currently it works with a single language, but my app has multiple languages. But I don't want to duplicate the language file for all languages. Can I re-use the same file in multiple languages without having to copy the file somewhere?
Use i18n files at ISO 639-1
representation.
That files allow you have any languages and use each "labels" with Ti.Locale.getString().
Also, you can use a require of file at app.js and put this variable like global.
language.js (for example):
var language = (function() {
var self = {
currentLanguage: 'en' // by default
};
var labels = {
msgHello: {
en: 'Hello World',
es: 'Hola Mundo'
}
};
self.changeLanguage = function changeLanguage(newLanguage){
self.currentLanguage = newLanguage;
};
self.getLabel = function getLabel(key, language){
if(typeof language !== 'undefined') {
return labels[key][language];
}
else return labels[key][self.currentLanguage];
};
return self;
}());
module.exports = language;
app.js (for example):
var appLanguage = require('language.js');
(function() {
Ti.API.info("Language: "+appLanguage.currentLanguage);
Ti.API.info("MSG Hello World (English): "+appLanguage.getLabel(msgHello));
Ti.API.info("MSG Hello World (Spanish): "+appLanguage.getLabel(msgHello, es));
}());
You can use appLanguage variable directly on any file.
It appears it is not possible to reuse a language file without copying it to all languages. However, the best solution to create a global go-to for parameters to be used in TSS files is to add a section to the config.json file.
A proper way to do this is:
"global": {
"design": {
"primaryColor": "red"
}
},
This can then be used by accessing Alloy.CFG.design.primaryColor.
The benefit for using the config.json file is that you can also theme the files, as described by Fokke Zandbergen.
This way, it is even better than using language files, because those couldn't be themed.
No, but you could use default strings like:
L('my_string','my default for this string');
In this example 'my_string' is a string withing your language file. If you only provide a file for English, you'll get the default setting for all other languages.
R

Environment-specific web.xml in grails?

What's the best way to build environment-specific web.xml entries in grails?
I need to make certain modifications for production only, as they break running locally.
Any thoughts?
You can create scripts/_Events.groovy with an event handler for the 'WebXmlEnd' event which is fired once Grails and the plugins have finished making their changes. Update the XML with plain search/replace or via DOM methods by parsing the XML and write out the updated file:
import grails.util.Environment
eventWebXmlEnd = { String filename ->
if (Environment.current != Environment.PRODUCTION) {
return
}
String content = webXmlFile.text
// update the XML
content = ...
webXmlFile.withWriter { file -> file << content }
}
Here's the solution that's i'm using, from the guy over at death-head.ch
first install the templates
grails install-templates
then customize the web.xml you'll find in src/templates/war/web.xml. I chose to make a web_dev.xml and a web_prod.xml and delete the web.xml. I wanted web_prod.xml to contain a security-constraint block. anyway...
Place the following in BuildConfig.groovy:
// #########################################################
// ## Can't use environment switching block because BuildConfig doesn't support it.
// ## #url http://jira.grails.org/browse/GRAILS-4260
// ## So use this workaround:
// ## #url http://death-head.ch/blog/2010/09/finally-solved-the-base-authentication-in-grails/
// #########################################################
switch ("${System.getProperty('grails.env')}") {
case "development":
if (new File("/${basedir}/src/templates/war/web_dev.xml").exists()) {
grails.config.base.webXml = "file:${basedir}/src/templates/war/web_dev.xml"
}
break;
default:
if (new File("/${basedir}/src/templates/war/web_prod.xml").exists()) {
grails.config.base.webXml = "file:${basedir}/src/templates/war/web_prod.xml"
}
break;
}
Good luck!
I've never tried it, but it should be possible to specify the grails.config.base.webXml parameter in BuildConfig.groovy dependant on the current environment.
There's a list of available BuildConfig settings here
EDIT
Actually, due to this issue, this isn't a way forward :-( Maybe passing the property like:
grails -Dgrails.config.base.webXml=/path/to/web.xml
Is all that's possible?

Resources