I have blog page on multiple languages and I use react-i18next library for translation.
I have one component called BlogPostPage where I show each post when it's opened, inside the component there is part for showing blog text like this:
import { useTranslation } from "react-i18next";
const [t] = useTranslation(["translation1", "overview"]);
..........
<Typography mb={2} component="p" variant="subtitle1">
{t(`text${state.id}1`)}
</Typography>
and my json translation file looks like this
{
"text51":"<h4>Welcome to our application</h4>",
}
So I want to put html code inside translation text since different post has different html code it really needs to be in json file and not in the component... is there any way that can be done?
Output of my code is:
<h4>Welcome to our application</h4>
Use the Trans component: https://react.i18next.com/latest/trans-component
<Trans i18nKey="text51">
<h4>Welcome to our application</h4>
</Trans>
With <0> instead of <h4>
"text51": "<0>Welcome to our application</0>"
Your issue is that react will try to escape any html it find in strings like this. If you absolutely need to do this you can use the following method:
<div dangerouslySetInnerHTML={{__html: t(`text${state.id}1`)}} />
Beware that there is a reason that react calls this prop dangerouslySetInnerHTML, and doing this is very much an anti-pattern.
Related
What I'm trying to do
A simple way to render the content of a markdown file when it's passed as a string to another component using .compiledContent (or even using .rawContnent)? Or even a better way than this as obviously usually in Astro we can use the <Content /> Component, but from my knowledge, I can't pass a component or this functionality to another component without using a <slot /> in the parent component.
I have some JS for the parent component and using a <slot/> instead of passing the props to the component would change things, so hopefully looking for a solution with using this.
My setup
Data stored in /src/data/experience as markdown files with a year and a description formatted as markdown in the content section of each file
A component called Tabs.astro which takes props of headings and contents which are both lists of strings
A page /src/pages/experience.astro with the Tabs component in it which is displaying this data
I take the below code to get the data from the markdown files and pass the years and descriptions to the Tab component.
experience.astro
---
import Tabs from "../components/Tabs.astro";
const jobs = await Astro.glob("../data/experience/*.md");
const years = jobs.map((job) => job.frontmatter.year);
const descriptions = jobs.map((job) => job.compiledContent);
---
<!-- My component taking the data to be rendered -->
<Tabs headings={years} contents={descriptions} />
Tabs.astro
And the component renders the info like so
<!-- Tabs -->
<div class="tabs">
<ul class="tabs-header">
{
headings.map((heading) => (
<li>{heading}</li>
))
}
</ul>
<ul class="tabs-content">
{contents.map((content) => <li class="tab">{content}</li>)}
</ul>
</div>
My current solution
At the moment using .compiledContent gets me the correct HTML, however it is all in a string so the HTML doesn't actually render.
What I'm looking for
Is there a native way in Astro to pass markdown as a prop to a component?
If not is there a manual and recommended way in Astro to convert a markdown string and sanitise it to protect against XSS attacks? (if this is a risk in Astro when rendered statically?)
If not what are your most recommended ways to render markdown and sanitise it in JS?
Thanks so much for your time and help! I'm loving using Astro
p.s Also happy to concede and just use a <slot/> in my component if needed... ;)
Astro has a set:html directive you can use in combination with a Fragment like this
<Fragment set:html={post.compiledContent()}/>
After a bit of struggling with this myself, the current solution from the Astro docs for a single file without looping is the following.
Import your file with {Content as YourAliasName} from '../yourPath/yourFileName.md'
Then just use it as a tag <YourAliasName />
Example from the docs for reference:
---
import {Content as PromoBanner} from '../components/promoBanner.md';
---
<PromoBanner />
https://docs.astro.build/en/guides/markdown-content/#the-content-component
I'm using Storybook to document some html components.
However, in order to create a story in mdx I have to use the Story component, meaning I can't use raw html and instead have to return my markup as a string:
import { Story } from '#storybook/addon-docs/blocks';
<Story name="Simple Button">
{`<button class="my-button">Download Now</button>`}
</Story>
Which renders the source code as a string:
Is there a way I can return clean markup or have the source show as true html? The source showing quotes and lack of syntax highlighting makes for poor documentation.
It seems that since v6.0.0-alpha.22 you can render any custom source code in Storybook.
Using the Canvas block's params object you can set custom source for your story.
import { Story, Canvas } from '#storybook/addon-docs/blocks';
<Canvas>
<Story name="custom source" height="100px" parameters={{ docs: { source: { code: `<button class="my-button">Download Now</button>` } } }}>
{`<button class="my-button">Download Now</button>`}
</Story>
</Canvas>
This renders the button in the story, and the source code uses raw HTML:
I am using an Angular Wrapper for JSON Editor like this:
<div *ngFor="let act of editedActions" class="w-100-p p-24">
{{act.test_step_id}}
<json-editor [options]="editorOptions" [(data)]="act.action_json" [(eventParams)]="act.test_step_id" (jsonChange)="changeStepActions($event)"></json-editor>
<button mat-raised-button class="w-100-p mt-24" color="primary" (click)="editRecordJson(act.test_step_id)">
<span>Update</span>
</button>
</div>
The problem is that eventParams should be different for each editor but it is not varying.
I think problem is this component code (but not sure) (This line is in the component taken from github):
#ViewChild('jsonEditorContainer', { static: true }) jsonEditorContainer: ElementRef;
The component is behaving like a singleton. Any help?
Edit: I edited this repo and added jsonchange event. Details here
You may want to use #ViewChildren with a direct reference to the component instead of a template variable string, to get all the JSON editors references:
#ViewChildren(JsonEditorComponent) jsonEditorContainers: QueryList<ElementRef>;
// ...
jsonEditorContainers.find(...);
It returns a QueryList that allows you to iterate through all ElementRef, and monitor the changes with an Observable changes.
What is eventParams? What is jsonChange? I could be wrong, but data doesn't seem to be two way bindable either, according to the source code.
It seems like you might be looking for something like this:
<div *ngFor="let act of editedActions" class="w-100-p p-24">
<json-editor [options]="editorOptions"
[data]="act.action_json"
(change)="changeStepActions($event, act.test_step_id)">
</json-editor>
</div>
You can then read the test_step_id in your changeStepActions method. If this works, I don't know how you made it compile in the first place.. are you using a CUSTOM_ELEMENTS_SCHEMA?
Its not necessary to use #ViewChildren for that you have to rewrite the entire code of component, make sure while using #ViewChild you pass correct editor reference.
As following
#ViewChild('carEditor' ) carEditor: JsonEditorComponent;
#ViewChild('mobileEditor') mobileEditor: JsonEditorComponent;
Stackblitz example for refernce :
Click here for code example
To use multiple jsoneditors in your view you cannot use the same editor options.
You should have something like:
<div *ngFor="let prd of data.products" class="w-100-p p-24" >
<json-editor [options]="makeOptions()" [data]="prd" (change)="showJson($event)"></json-editor>
</div>
makeOptions = () => {
return new JsonEditorOptions();
}
I'm working on a large React project where we are receiving data from an API we don't control Occasionally we need to receive an HTML string with inline styles and insert all of it directly in our component. It will be passed to us as a string -- I've not gotten a clear answer from the backend team, but I think it will be something like
<textarea rows='1' cols'50' >Some text with <span class='special style'>special styles applied</span></textarea>
How do I insert this into my react component correctly (and safely)? Simply something like the following?
const myHTMLStringFromAPI = getApiStuff()
render(){
return <div>{myHTMLStringFromAPI}</div>
}
You can do what using dangerouslySetInnerHTML
dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. This is used because setting innerHTML directly is risky.
const myHTMLStringFromAPI = getApiStuff()
render(){
return <div dangerouslySetInnerHTML={{__html:`<textarea rows='1' cols'50' >Some text with <span class='special style'>special styles applied</span></textarea>`}}>{myHTMLStringFromAPI}</div>
}
I'm putting together an application in which there are many modals. As I do not want to repeat the code of the modal, I want to assemble a base component that has the minimum structure and then with that structure to be able to assemble the different modals and to carry what I need inside (form, text, images)
An example of what I am looking to do
<app-modal-base>
<app-form></app-form>
<app-modal-base>
I hope you understand what I'm looking for. In case you can not, someone found an alternative solution?
Thanks
In your base modal template, include the <ng-content></ng-content> tag. When you display your modal, you can use it as follows:
<Modal>
<div id="mydiv">
<p> Simple paragraph </p>
<form>...</form>
</div>
</Modal>
The modal will include what you have included between the <Modal></Modal> tags at the place where the <ng-content></ng-content> tags are in the template for the base modal component. It would look like:
template: `
<div id="closeButton"></div>
<ng-content></ng-content>
`
This information is gathered from this source, and I can't seem to find official docs about this. You might have to try it out.