Using variables with translate filter in AngularJs - angularjs

I am working on an AngularJs project and I am using the translate filter the following way:
<h2>{{'This is my text' | translate}}</h2>
It works fine, but I would like to be able to use variables in my translations. Here is what I have tried:
In the controller:
vm.text = "This {{toReplace}} is a variable.";
vm.myVariable = "random value";
In the html:
<h2>{{vm.text | translate:'{ toReplace: vm.myVariable }'}}</h2>
It doesn't replace {{toReplace}} with the content of myVariable. Instead, the page displays "This {{toReplace}} is a variable."
What should I do to make this work ?

Have you tried with the directive rather than the filter ? Something like this :
<h2 translate="vm.text" translate-values={'toReplace':vm.myVariable}"></h2>

vm.text must contain a valid translate key, which you should define in your language files. The value of the translate key will be "This {{toReplace}} is a variable.". Then your HTML should render correctly.
If you just want to render this text without internationalization support, you could just do this:
<h2>This {{vm.toReplace}} is a variable.</h2>

Here is the solution that has worked for me, considering 'myVariable' is a variable defined in my controller:
<h2 data-translate>This {{vm.myVariable}} is a variable</h2>
The tricky part is that, just like when using the translate filter, the text in the element is not the text being displayed, but the ID of the element to translate. In the translation files (po), you will have to have an element with the ID 'This {{vm.myVariable}} is a variable', including the name of the variable. If you need to display the same text but with data coming from a different variable, you would have to declare a different translation with its own ID, even though only the variable part of the text is different.
For exemple, this would have to be a different entry in the translation files:
<h2 data-translate>This {{vm.myVariable2}} is a variable</h2>

Related

How can my template include an element whose type is determined by an expression in angularjs?

It's 2022 and sadly I'm learning AngularJS (already past end of life!)
I need need to use what might be called a dynamic element/component. Pseudocode example:
In controller:
this.theElementName = 'b';
In the template:
<{{$ctrl.theElementName}}>this is some text</{{$ctrl.theElementName}}>
I would want this to create <b>this is some text</b>.
The reason is that I want to generate an array of different directives to render, and I don't want code like:
<b ng-if="$ctrl.theElementName === 'b'">this is some text</b>
<div ng-if="$ctrl.theElementName === 'div'">this is some text</div>
<directive-abc ng-if="$ctrl.theElementName === 'directive-abc'">this is some text</directive-abc>
...
In Svelte, it's
<svelte:element this={theElementName} />
In Vue it's
<div :is="theElementName" />
EDIT: in response to the reluctant 'that person', clarifying the use-case
Consider a user-configurable UI. The result of the configuration might be an array list of components desired. I would then need to loop and output those different components in my template. Of course the components would need a standard interface for properties passesd in, events emitted etc. but that can all be designed for.
My code could do a big switch statement, but that requires prior knowledge of every possible component that might be used now or in the future. By doing it the way I intend to, however, a future person could add a component without needing to touch this code.
You can write directive my-directive to use:
<div my-directive="$ctrl.theElementName">...
to generate:
<div><component-a>...
<div><component-b>...
<div><component-c>...
All directive should do is to generate html string and compile it:
element.append($compile('<' + scope.myDirective + '>...')(scope))
(also remember to update content in onChanges if you want to support it)
Directive may also copy certain/all attributes from original element etc.
P.S. you should be cautious e.g. if component name comes from database that may allow injections.
Not a brilliant solution, but documenting what is more of a workaround.
ng-include can be used to source another template file. That file can contain the component you need to include.
<ng-include src="'/path/to/' + theElementName + '.html'"></ng-include>

Angular render markup that is nested

I get JSON like this
{
"lots of":"keys"
"description" : {
"key":"Some sample key",
"value":"This is the markup™"
}
}
from server and I ultimately iterate the description objects and populate table rows with two columns: one for the key and one for the value.
I have tried putting on my <td> tag ng-bind-html as well as injecting $sce into my controller and using trustAsHtml but so far the string always displays as it is in the JSON. Not every value will be HTML but I can easily detect based on the key if HTML is a possibility. It seemed when I put in the directive on the td it did not display anything if no HTML was present. I am interested in using something that can allow HTML in the value but not require it so I can display either
HTML fragment
<tr ng-repeat="(key, val) in record.description">
<td>{{key}}:</td>
<td>{{val}}</td>
</tr>
I created a quick fiddle here:
https://jsfiddle.net/frishi/mvw97s3q/6/
I used angular-sanitize, which I am not sure you mentioned injecting in your module dependency list. Either way, the example works simply by using ng-bind-html
Relevant docs page: https://docs.angularjs.org/api/ng/directive/ngBindHtml
It works by using the directive ng-bind-html on the element you want to display the HTML string in. You use it like so:
<p ng-bind-html="data.firstName"></p>
assuming that data.firstName = "<strong>FeeFee</strong>" or something like that.
I would also like to add that Angular does not allow this natively because of legitimate security concerns. That and the fact that allowing arbitrary HTML to be rendered might not always produce desirable results. Your page layout could quite possibly break because of some HTML you allowed to be passed through.
Angular was designed with security in mind, and will prevent you from displaying HTML from raw strings whenever possible - to prevent various injection attacks.
Here is workarround for your problem: AngularJS: Insert HTML from a string. Generally you should use ng-bind-html insted of ng-bind (this is used by curly braces).

ng-bind-html with ng-sanitize' linky output tags as strings

If I try to use both ng-sanitize's linky filter with ng-bind-html directive, it will transform initial string
Well, <b>this is bold</b>, but this should become link http://www.example.com Lets test it!
to one having link transformed to html link, but not having bold text - it will be outputed as text having tags in it.
Here's [DEMO]
My question is how do I get in result both bold text and normal html link if initialy I have just as string having some text surrounded by tags and text that looks like a link??
Plunkr Demo
You could write a custom filter to do the work of linky and put the tags back in... (this probably isn't super robust and I'm not the best at regexes, but if it works for everything you need it to, then it gets the job done.)
module.filter('linkyWithHtml', function($filter) {
return function(value) {
var linked = $filter('linky')(value);
var replaced = linked.replace(/\>/g, '>').replace(/\</g, '<');
return replaced;
};
});
Usage:
<div ng-bind-html="expr | linkyWithHtml"></div>

Angularjs translate in nested tag

Good day,
I'm trying to translate using the directive way this portion of html
<h1>First text to translate<small>Second text to translate</small></h1>
But I encounter some difficulties. For example if I try:
<h1 translate>KEY<small>Second text to translate</small></h1>
the key will not be translated and I see it on the page and if I try:
<h1 translate="KEY"><small>Second text to translate</small></h1>
this time the key is translated but the second text disappear.
To make it work I must use the translate service inside the controller or remove the nesting. Any advice?
You can use it as a filter instead of directive:
<h1>{{'KEY' | translate}}<small>{{'Second text to translate' | translate}}</small></h1>
See https://angular-translate.github.io/docs/#/api/pascalprecht.translate.filter:translate

angular-foundation and angular-translate: apply translation into attribute back-text

I'm using angular-translation and angular-foundation modules with AngularJS and have defined Foundation top-bar like this:
<top-bar custom-back-text="true" back-text="My back text">
[...]
</top-bar>
I need to apply translate filter to My back text. Already tried these two solutions but with no success:
example 1 - CODE
<top-bar custom-back-text="true" back-text="'BACK.KEY' | translate">
example 1 - TEXT IN MENU
BACK.KEY
example 2 - CODE
<top-bar custom-back-text="true" back-text="{{ 'BACK.KEY' | translate }}">
example 2 - TEXT IN MENU
'BACK.KEY' | translate
Do I something wrong or is there no possibility to achieve this with these two modules?
Used versions
angular-translate: 2.4.2
angular-foundation: 0.5.1
If you check the js source code of foundation you will find this piece of code that handles back button
if (settings.custom_back_text == true) {
$('h5>a', $titleLi).html(settings.back_text);
} else {
$('h5>a', $titleLi).html('« ' + $link.html());
}
$dropdown.prepend($titleLi);
So it creates new element and adds to dropdown, result of which is that it copies the value you specified in the back_text. By that time "translate" is not resolved so it copies whatever you put there.
A quick hack to do to solve it you could listen for language change by doing
$rootScope.$on("$translateChangeSuccess", function...
As you can see in the piece of code from foundation.js it creates "a" element inside "h5", so you can do something like this
$rootScope.$on("$translateChangeSuccess", function(){
angular.element(".dropdown h5>a").html($filter('translate')('BACK'))
})
where "BACK" is the key used for translation.
But keep in mind that it's not a good practice to manipulate DOM inside controller, so you may create directive for that.
Though there may be better way to achieve it, this could be just quick hack to do the thing.

Resources