TAPi18n: how to construct the key to be translated dynamically? - meteor

I'm trying to add a prefix to the keys to be translated. This is one of my attempts:
<label for="{{n}}">{{_ 'input_label_{{n}}' }}</label>
<input name="{{n}}" placeholder="{{_ 'input_placeholder_{{n}}' }}">
Obviously it does not work because you can't nest {{ ... }}'s.
I've also tried creating a helper:
{{tr 'input_label' n}}
tr: function(prefix, fieldName) {
return TAPi18next.t(prefix + '_' + fieldName);
}
But it comes back untranslated. I assume because I'm calling TAPi18n as a static and not an instance of it, but I don't know how else to do it.
These are just two of many attempts.
I will have hundreds of inputs, and I want to avoid sending all the translation keys to the input template, since it's redundant information. The key variations can easily be made by adding prefixes.
Can you think of any way to generate the key values dynamically?

Use the second approach, but with TAPi18n.__ rather than TAPi18next.t.
Unlike TAPi18next.t, TAPi18n.__ reactively updates when the user's language choice is changed and the language has finished downloading. I'm guessing the problem is that the language choice hasn't quite come through when the template is first rendered, so TAP18next.t returns the strings in the default language (English), and doesn't update when the language changes. Using TAPi18n.__ instead fixes this.

Related

SAP UI5 binding by reference to another value

I have a large model with many levels and attributes and I want to have one Input in my XML view which will always edit 1 attribute from the model, but every time it will be a different attribute.
I want to edit for example attributes on following paths:
myModel>/user/0/surname
myModel>/user/1/name
myModel>/user/2/nickname
myModel>/user/3/email
Let's say that now I am interested in editing the nickname of user nr2 so I will save its path to a variable:
myModel.setProperty("currentlyEditedPath", "myModel>/user/2/nickname");
And I want to define my Input like this:
<Input value="{myModel>/currentlyEditedPath}" >
And what happens is that UI5 will allow me to edit the string "myModel>/user/2/nickname" it self. But its wrong. I only want to use the string as a reference to some other value deep in the model which should be modified and updated. I should probably write something like this, but I cannot find the correct way:
<Input value="{ ${myModel> ${myModel>/currentlyEditedPath} } } " >
Any ideas, please? .. as simple as possible. Best inline.
I think the Element binding is the good way. Feel free to comment on this:
var oInput = sap.ui.core.Fragment.byId("myFragmentID","myInputID");
oInput.bindElement("myModel>/user/2");
oInput.bindProperty("value", "myModel>nickname");
Or I can also place the value to the XML:
<Input value="{myModel>nickname}" >

How can I translate input use ngx-translate?

<input type="text" name="title" [(ngModel)]="dataAdd.titleEN">
<input type="text" name="title" [(ngModel)]="dataAdd.titleFR">
I need to show two title but different language
If I click of button en show text in English or fr show text in French
and save in variable string
Note: I need unique variable for unique data insert in Firestore
dataAdd = {
titleEN: '',
titleFR: '',
}
this.translateList = this.afs.collection('translates');
this.translateList.doc('en').set({
TITLE_FOR_RENT: this.dataAdd.titleEN,
});
this.translateList = this.afs.collection('translates');
this.translateList.doc('fr').set({
TITLE_FOR_RENT: this.dataAdd.titleFR,
});
In my opinion you have assumed wrongly the usage of ngx-translate, this package is used in order to support multiple pre defined languages , for example if you want to support en and fr , beforehand you must have a .json file for each desired language, with the following KvP structure => where the key is a universal key (some string that is the same in each json file), which is used to map values to the translations from the .json files. You can check out the official StackBlitz Demo for detailed example of the usage.
In order to achieve the result that you described, I would suggest to use something like Cloud Translation API provided by Google, which is able to translate live user inputs (or whatever you pass to the API), after that depending on your strategy you might display the response from the API directly to the client, or load it first in the ngx-translate and then display it to the client.
Note:
I would go for the first option, because I assume in your case filling the browser memory is unnecessary (because when loading the translation trough in ngx-translate you are just feeling one big js object behind the scenes)

Adding fields dynamically to Share form

I want to add a text field for each file that is added to the attached package items in alfresco to write notes regarding each file, is it possible to do?
I have implemented something that could be reused for your use case.
You can define a property with multiple values that will contain the list of notes associated with each attachment.
There is a simple trick to post a property with multiple values: add "[]" to the name of the property. For example:
<input id="template_x002e_edit-metadata_x002e_edit-metadata_x0023_default_prop_someco_notes_0"
name="prop_someco_notes[]"
tabindex="0"
type="text"
value="Meeting minutes"
title="Notes"
noderef="workflow://...."
>
<input id="template_x002e_edit-metadata_x002e_edit-metadata_x0023_default_prop_someco_notes_1"
name="prop_someco_notes[]"
tabindex="1"
type="text"
value="Meeting minutes"
title="Notes"
noderef="workflow://...."
>
As you can see, the name of the input ends with []. Both input textfields have the same name.
The Alfresco Form Engine will consider these two inputs as the value for the property with multiple values: "someco:notes".
The bigger problem is that you need to generate this html with some smart javascript and free marker template.
You can write a custom free marker template to render the initial html: if a user opens a task on which documents have been already attached, you will need to generate the list of inputs using a custom control (you can of course start from textfield.ftl).
It won't be easy to generate the initial list because unfortunately Alfresco returns the list of values as a single comma separated value.
You can customise the webscript that injects the model in the free marker template "org.alfresco.web.scripts.forms.FormUIGet" to pass an array instead of a csv.
A quicker and dirtier solution is to split the csv value. In share-config-custom.xml, you can specify what textfield.ftl show use as a separator instead of the comma.
When a user adds/remove elements from the package, you can intercept the update and add/remove the correspondent note. Notice that I have added the filed "noderef" to each input so it is possible to know the relation between the notes and the nodes in the package.
UPDATE:
For the associations (used for example to define the package in a workflow task), Share uses a javascript library called "object finder" (or "object picker"). This library fires an event called "formValueChanged" that you can intercept:
YAHOO.Bubbling.fire("formValueChanged",
{
eventGroup: this,
addedItems: addedItems,
removedItems: removedItems,
selectedItems: selectedItems,
selectedItemsMetaData: Alfresco.util.deepCopy(this.selectedItems)
});

Meteor how to save templates in mongo

I want to give my users the possibility to create document templates (contracts, emails, etc.)
The best option I figured out would be to store these document templates in mongo (maybe I'm wrong...)
I've been searching for a couple of hours now but I can't figure out how to render these document template with their data context.
Example:
Template stored in Mongo: "Dear {{firstname}}"
data context: {firstname: "Tom"}
On Tom's website, He should read: "Dear Tom"
How can I do this?
EDIT
After some researches, I discovered a package called spacebars-compiler that brings the option to compile to the client:
meteor add spacebars-compiler
I then tried something like this:
Template.doctypesList.rendered = ->
content = "<div>" + this.data.content + "</div>"
template = Spacebars.compile content
rendered = UI.dynamic(template,{name:"nicolas"})
UI.insert(rendered, $(this).closest(".widget-body"))
but it doesn't work.
the template gets compiled but then, I don't know how to interpret it with its data context and to send it back to the web page.
EDIT 2
I'm getting closer thanks to Tom.
This is what I did:
Template.doctypesList.rendered = ->
content = this.data.content
console.log content
templateName = "template_#{this.data._id}"
Template.__define__(templateName, () -> content)
rendered = UI.renderWithData(eval("Template.#{templateName}"),{name:"nicolas"})
UI.insert(rendered, $("#content_" + this.data._id).get(0))
This works excepted the fact that the name is not injected into the template. UI.renderWithData renders the template but without the data context...
The thing your are missing is the call to (undocumented!) Template.__define__ which requires the template name (pick something unique and clever) as the first argument and the render function which you get from your space bars compiler. When it is done you can use {{> UI.dynamic}} as #Slava suggested.
There is also another way to do it, by using UI.Component API, but I guess it's pretty unstable at the moment, so maybe I will skip this, at least for now.
Use UI.dynamic: https://www.discovermeteor.com/blog/blaze-dynamic-template-includes/
It is fairly new and didn't make its way to docs for some reason.
There are few ways to achieve what you want, but I would do it like this:
You're probably already using underscore.js, if not Meteor has core package for it.
You could use underscore templates (http://underscorejs.org/#template) like this:
var templateString = 'Dear <%= firstname %>'
and later compile it using
_.template(templateString, {firstname: "Tom"})
to get Dear Tom.
Of course you can store templateString in MongoDB in the meantime.
You can set delimiters to whatever you want, <%= %> is just the default.
Compiled template is essentially htmljs notation Meteor uses (or so I suppose) and it uses Template.template_name.lookup to render correct data. Check in console if Template.template_name.lookup("data_helper")() returns the correct data.
I recently had to solve this exact (or similar) problem of compiling templates client side. You need to make sure the order of things is like this:
Compiled template is present on client
Template data is present (verify with Template.template_name.lookup("data_name")() )
Render the template on page now
To compile the template, as #apendua have suggested, use (this is how I use it and it works for me)
Template.__define__(name, eval(Spacebars.compile(
newHtml, {
isTemplate: true,
sourceName: 'Template "' + name + '"'
}
)));
After this you need to make sure the data you want to render in template is available before you actually render the template on page. This is what I use for rendering template on page:
UI.DomRange.insert(UI.render(Template.template_name).dom, document.body);
Although my use case for rendering templates client side is somewhat different (my task was to live update the changed template overriding meteor's hot code push), but this worked best among different methods of rendering the template.
You can check my very early stage package which does this here: https://github.com/channikhabra/meteor-live-update/blob/master/js/live-update.js
I am fairly new to real-world programming so my code might be ugly, but may be it'll give you some pointers to solve your problem. (If you find me doing something stupid in there, or see something which is better done some other way, please feel free to drop a comment. That's the only way I get feedback for improvement as I am new and essentially code alone sitting in my dark corner).

TAL Condition in Plone to hide HTML if it's a Document (Page)

I'm trying to modify my /portal_view_customizations/zope.interface.interface-plone.belowcontenttitle.documentbyline template with a tal expression, so that the document's author and the modification date do not show if the current portal type is a Document (Page). I don't mind if it shows for News Items, which are time sensitive, but not the Documents/Pages.
This is my failing Plone TAL expression:
<div class="documentByLine"
id="plone-document-byline"
i18n:domain="plone"
tal:condition="view/show and not:python:here.portal_type == 'Document'">
...
I've also tried:
<div class="documentByLine"
id="plone-document-byline"
i18n:domain="plone"
tal:condition="view/show and not:context/portal_type='Document'">
but still no luck. The tracebacks are pretty cryptic and don't relate to the TAL expression. However, if I get rid of my condition for portal_type, then it works again. Any thoughts are appreciated. A manual would be good, but I've looked at the official ones, and they don't mention this.
TAL's underlying TALES, the expression-engine of which TAL makes use of, doesn't support the mixing of expression-types in one expression. It's syntax allows only one expression-type to be specified (defaults to 'path', if omitted, btw), as no delimiter is provided (like a semicolon for chaining several TAL-statements in one element, e.g.).
But instead of mixing three expression-types you can use one python-expression, try:
python: view.show and context.portal_type()!='Document'
Update:
If you have customized a Plone's default-template via portal_view_customizations ('TTW'), now restricted python-methods cannot be accessed, that' why view/show throws an error.
It returns the allowAnonymousViewAbout-property of the site-properties, you can also check this condition yourself and your expression looks like:
tal:define="name user/getUserName"
tal:condition="python:test(name!='Anonymous User') and context.portal_type()!='Document';
Quick'n'dirty alternative:
Do it with CSS:
body.userrole-anonymous .documentByLine {display:none}
body:not(.template-document_view) .documentByLine {display:block}
This will render the hidden elements, but it's helpful for prototyping and such, or 'quickfixes' (no admin available, etc.).

Resources