How to override the default Localization message of ABP exceptions? - entity-framework-core

I am developing an ABP application and I want to override the "InternalServerErrorMessage" with a custom message. My aim is to set this override to the entire application, so I don't need to write try-catch statements throughout the whole system.
The JSON file with all Exception messages can be found at: https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.ExceptionHandling/Volo/Abp/ExceptionHandling/Localization/en.json
I tried to write some code at DomainSharedModule.cs and inside the Localization Folder (both are located at the Domain.Shared folder), but unfortunately it did not work.

You can create a folder under the Localization folder in the *.Domain.Shared project and override the localization value by your need:
/Localizations/MyProject
{
"culture": "en",
"texts": {
"InternalServerErrorMessage": "<your localization value>",
}
}
Then, you can configure it in your MyApplicationDomainSharedModule.cs as below:
Configure<AbpLocalizationOptions>(options =>
{
//...
//add the following code
options.Resources
.Get<AbpExceptionHandlingResource>() //exception handling localization resource
.AddVirtualJson("/Localization/MyProject"); //your localization folder path
options.DefaultResourceType = typeof(MyProjectNameResource);
});
Also, ensure you set the localization files as EmbeddedResource in your *.Domain.Shared.csproj file. Example: https://github.com/abpframework/abp/blob/dev/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain.Shared/MyCompanyName.MyProjectName.Domain.Shared.csproj#L22-L29
Resources
https://docs.abp.io/en/abp/latest/Localization
https://community.abp.io/posts/how-to-override-localization-strings-of-depending-modules-ba1oy03l

Related

Virtual File System and Areas

I'm trying to use Areas in my ASP.NET Core ABP project like so:
Folder Structure
I'm trying to add a single file bundle like this:
<abp-script src="/Areas/Community/Pages/Mentors/Index.js" />
When I try running the page I get the following error:
AbpException: Could not find the bundle file '/Areas/Community/Pages/Mentors/Index.js' from IWebContentFileProvider
The documentation says the files can be located in Pages, Views, Components, and Themes but it seems limiting if it doesn't also support areas. Do I need to add a route somewhere so the virtual file system can find it?
Update:
I found the source code in \Volo.Abp.AspNetCore\Volo\Abp\AspNetCore\VirtualFileSystem\AbpAspNetCoreContentOptions.cs
where it sets the AllowedExtraWebContentFolders list:
AllowedExtraWebContentFolders = new List<string>
{
"/Pages",
"/Views",
"/Themes",
"/Components"
};
Is there any way to add to this list?
You can configure it in the module's ConfigureServices method.
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAspNetCoreContentOptions>(options =>
{
options.AllowedExtraWebContentFolders.Add("/Areas");
});
}

SAP custom translations for standard SAPUI5 application

I am currently implementing an extension to a standard application from SAP Marketing.
The extension contains new texts that need to be translated into different languages. In my previous extensions I could use the translation key of the standard application for my extension as well. The first line in the i18n.properties file in this case was always structured as follows:
# SAPUI5 TRANSLATION-KEY XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
However, in the standard app that I'm currently editing, it looks like this:
# This is the resource bundle for Campaigns
# __ldi.translation.uuid = 8e965d5e-c905-4b60-ac2a-205abb14046
In transaction se63, the translation key (is it even a translation key?) is not found - either with hyphens or without. Furthermore, in the standard app, the translations are kept in a single file for each language (e.g., i18n_de.properties). That's why I'm not sure if there's even a translation key for this standard app.
I don't want to create a new translation key for my extension and use this one. Once I did this, all the translations of the standard app had to be maintained for the new translation key as well.
Is anyone familiar with this type of translation? How can I maintain the translations for my extension?
Best Regards,
Christian
I found some solution to my problem:
I generated a new translation key by running program /UI5/TEXT_FILE_GEN_TRANS_KEY in transaction se38
I created a new folder i18n and added a i18nCustom.properties file to it. Then I added the translation key and default translations to the file just like for a regular i18n.properties file.
In the next step, I added the following code to the sap.ui5 property of the extension's manifest.json file to initiate the custom translation file:
"models": {
"i18nCustom": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "<Your Component>.i18n.i18nCustom"
}
}
}
Please note that you have to use something like {i18nCustom>property} in your view now instead of using i18n model.
To enhance the standard translation file with the custom one, I added the following code to the BaseController. You could also add the code only in the controller whose view is using the custom translations.
onBeforeRendering: function() {
var i18n = this.getModel("i18n"); // Get the standard i18n file
var sBundleURL = this.getModel("i18nCustom").getResourceBundle().oUrlInfo.url;
i18n.enhance({bundleUrl:sBundleURL}); // Merge the custom i18n file with the standard one
}
Hope this helps if someone has the same problem.

How to override an HTML file in a custom module

I am developing a custom module for a payment method in magento 2. Currently I am using cc-form.html from the vendor directory and the module is working fine. see below path.
vendor/magento/module-payment/view/frontend/web/template/payment/cc-form.html
Is there any way to override the HTML file?
Yes, there is. You can look in pub static to see how path to static asset constructed.
How it works
Every asset is accessible from the page by itenter code heres "RequireJS ID". It similar to real path, but varied.
For example file http://magento.vg/static/adminhtml/Magento/backend/en_US/Magento_Theme/favicon.ico.
It's real path is /app/code/Magento/Theme/view/adminhtml/web/favicon.ico.
It's RequireJS ID is Magento_Theme/favicon.ico. This means that file could be accessible via require("text!Magento_Theme/favicon.ico") or similar command.
You can find that RequireJS ID consist with module name and useful part of path (after folder web).
How can I replace a file
So you have file
vendor/magento/module-payment/view/frontend/web/template/payment/cc-form.html
On the page it loaded with src as
http://magento.vg/static/frontend/Magento/luma/en_US/Magento_Payment/template/payment/cc-form.html
So its RequireJS ID is
Magento_Payment/template/payment/cc-form.html
Side note: Inside UI components stuff it equals to Magento_Payment/payment/cc-form. Words "template" and ".html" are added automatically.
And now you can replace this file for application via RequireJS config
var config = {
"map": {
"*": {
"Magento_Payment/template/payment/cc-form.html":
"<OwnBrand>_<OwnModule>/template/payment/cc-form.html"
}
}
};
This code snippet you place in requirejs-config.js file in your module. That is all.

Can't override the standard skeleton views in Symfony2 GeneratorBundle

I don't manage to override the skeleton views of the generatorBundle.
I've first tried by adding my view in /app/Resources/SensioGeneratorBundle/skeleton/crud/views/index.html.twig
It didn't worked so I tried to create a new Bundle extending SensioGeneratorBundle and copy the my view in its Resources folder.
I already manage to use themes for twig forms, but I need to personalize the views generated by the doctrine:generate:crud command.
First of all: The corresponding skeleton views are located here:
vendor/bundles/Sensio/Bundle/GeneratorBundle/Resources/skeleton/crud
Quick and dirty you should be fine by overriding these view files - but thats not what we want ;)
In:
vendor/bundles/Sensio/Bundle/GeneratorBundle/Command/GenerateDoctrineCrudCommand.php
there is an accessor for the Generator:
protected function getGenerator()
{
if (null === $this->generator) {
$this->generator = new DoctrineCrudGenerator($this->getContainer()->get('filesystem'), __DIR__.'/../Resources/skeleton/crud');
}
return $this->generator;
}
One can try to override this method in your extending Bundle and set a different $skeletonDir in the constructor.
Edit:
Quick example in my test environment how it can be achieved (I only made a quick test ;):
Generate a new bundle for the custom generator: php app/console generate:bundle and follow the instructions. A route is not needed. I chose for this example: Acme/CrudGeneratorBundle (Or use an existing bundle)
Create a folder called "Command" in the newly created bundle directory.
Place a command class in this folder.
<?php
//src/Acme/CrudGeneratorBundle/Command/MyDoctrineCrudCommand.php
namespace Acme\CrudGeneratorBundle\Command;
use Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator;
class MyDoctrineCrudCommand extends \Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand
{
protected function configure()
{
parent::configure();
$this->setName('mydoctrine:generate:crud');
}
protected function getGenerator()
{
$generator = new DoctrineCrudGenerator($this->getContainer()->get('filesystem'), __DIR__.'/../Resources/skeleton/crud');
$this->setGenerator($generator);
return parent::getGenerator();
}
}
Copy the vendor/bundles/Sensio/Bundle/GeneratorBundle/Resources/skeleton/crud to your Resources (in my example "src/Acme/CrudGeneratorBundle/Resources/crud")
This was the best solution for me:
symfony2-how-to-override-core-template
doesn't add a command but modifies the skeleton for that particular bundle.

HTML5 Offline GWT APP

I am trying to build a offline gwt app using HTML5 cache manifest and
local storage, but to do that, i need to build the manifest file
listing all the GWT generated files, right?
Can i do this during the compile process or is it better to do this in
a shell script?
This should be done using a Linker, so that your resources are automatically added to the manifest at compile time. I know there exists an HTML5 cache manifest linker, since the GWT team has mentioned it a few times, but I don't know where the source is.
The closest alternative (and probably a good starting point for writing an HTML5 linker) is the Gears offline linker. Gears' offline manifests are pretty similar to HTML5's, so it's probably a matter of changing a few lines to make it work.
There's also an informative video about using GWT linkers to have your app take advantage of HTML5 Web Workers.
I just had to do this other day at work. Like the previous answer says, you just need to add a linker. Here's an example of one that creates a manifest file for the Safari user agent based on a template file.
// Specify the LinkerOrder as Post... this does not replace the regular GWT linker and runs after it.
#LinkerOrder(LinkerOrder.Order.POST)
public class GwtAppCacheLinker extends AbstractLinker {
public String getDescription() {
return "to create an HTML5 application cache manifest JSP template.";
}
public ArtifactSet link(TreeLogger logger, LinkerContext context, ArtifactSet artifacts) throws UnableToCompleteException {
ArtifactSet newArtifacts = new ArtifactSet(artifacts);
// search through each of the compilation results to find the one for Safari. Then
// generate application cache for that file
for (CompilationResult compilationResult : artifacts.find(CompilationResult.class)) {
// Only emit the safari version
for (SelectionProperty property : context.getProperties()) {
if (property.getName().equals("user.agent")) {
String value = property.tryGetValue();
// we only care about the Safari user agent in this case
if (value != null && value.equals("safari")) {
newArtifacts.add(createCache(logger, context, compilationResult));
break;
}
}
}
}
return newArtifacts;
}
private SyntheticArtifact createCache(TreeLogger logger, LinkerContext context, CompilationResult result)
throws UnableToCompleteException {
try {
logger.log(TreeLogger.Type.INFO, "Using the Safari user agent for the manifest file.");
// load a template JSP file into a string. This contains all of the files that we want in our cache
// manifest and a placeholder for the GWT javascript file, which will replace with the actual file next
String manifest = IOUtils.toString(getClass().getResourceAsStream("cache.template.manifest"));
// replace the placeholder with the real file name
manifest = manifest.replace("$SAFARI_HTML_FILE_CHECKSUM$", result.getStrongName());
// return the Artifact named as the file we want to call it
return emitString(logger, manifest, "cache.manifest.");
} catch (IOException e) {
logger.log(TreeLogger.ERROR, "Couldn't read cache manifest template.", e);
throw new UnableToCompleteException();
}
}
}
Use the gwt2go library's GWT Application Manifest generator to do precisely that. That was easy. :)