TAPi18n: How to show text in several languages side by side? - meteor

It seems tapi18n is designed to only have one active language at any given time.
I'm showing a form which includes the same field in several languages. I want to translate the labels and placeholders, because it's useful information for the people filling in the forms, but since I only have access to the current language, I can't show words from others.
I'd like this:
## Description ##
English
[ enter the description ... ]
Español
[ enter the description ... ]
Deutsch
[ enter the description ... ]
to look like this:
## Description ##
English
[ enter the description ... ]
Español
[ introduzca la descripción ... ]
Deutsch
[ placeholder in german... ]
I can think of hacks like creating a pre-processor that copies keys like { "description_placeholder_$$": "introduzca la description" } from each json file to every other json file replacing the $$ to the language code, so each language has all the keys containing $$ from every other language.
Another trick would be to load all the json files into memory, independently from tapi18n, and access the required words directly.
Any more elegant ways to solve this?

As #kyll mentioned, this is how it should work:
TAPi18n.__('amusing spaghetti', { lng: 'ru'});
But it fails to load languages on demand. As a work around, I preload languages on client side and set a session variable to indicate that all languages have been loaded.
var langs = [
{ code: 'en', name: 'English' },
{ code: 'es', name: 'Español' },
{ code: 'de', name: 'Deutsch' }
];
Meteor.startup(function () {
_.each(langs, function(lang) {
TAPi18n._loadLanguage(lang.code).done(function() {
Session.set('langsLoaded',
langs.length == TAPi18n._loaded_languages.length);
});
});
});
Then, in a template I have:
{{trToLang 'amusing spaghetti' 'ru'}}
And finally in a helper:
trToLang: function(key, lang) {
return Session.get('langsLoaded') ? TAPi18n.__(key, { lng: lang }) : '';
}
The session variable is needed because without it sometimes the languages are not loaded before the template renders, and that breaks TAPi18n.
I hope someone posts a more beautiful solution.

Don't know if this is still relevant, but I saw it in use in Sam's md-blog package, maybe it will help to see someone else's implementation?
https://github.com/xolvio/md-blog
HTH

Related

How to use an array of objects on a foundation email template?

Im using foundation emails, i can use variables on a template by wrapping them in a raw tag, for example:
<raw><%= myVariable %></raw>
Now, I need to add attachments, and attachmeants come as an array with this form:
attachmentsData: [
{
id: '301e165f-130e-4f89-83da-a49ff43172ce_Screenshotfrom2018-11-1916-43-01.png',
title: 'Screenshotfrom2018-11-1916-43-01.png',
url: 'https://s3.eu-central-1.amazonaws.com/dev-messaging-attachments/301e165f-130e-4f89-83da-a49ff43172ce_Screenshotfrom2018-11-1916-43-01.png',
},
{
id: '301e165f-130e-4f89-83da-a49ff43172ce_Screenshotfrom2018-11-1916-43-02.png',
title: 'Screenshotfrom2018-11-1916-43-02.png',
url: 'https://s3.eu-central-1.amazonaws.com/dev-messaging-attachments/301e165f-130e-4f89-83da-a49ff43172ce_Screenshotfrom2018-11-1916-43-02.png',
},
],
On the documentation it also says that i can loop over arrays that are declared in src/data in yml format.
However in my case i need the array of objects to come from the backend.
but if it comes from the backend it i have to parse it with the raw tags.
But if use the raw tags i cant use the each helper:
https://foundation.zurb.com/emails/docs/panini.html#custom-data
Do you know how to loop over this array?
note that, If i do <raw><%= myArray[0].name %></raw> this works and prints the right value.
Any tips? Thanks
If <raw><%= myArray[0].name %></raw> works, then the following should work too.
<% myArray.forEach(data => { %>
<raw><%= data.name %></raw>
<% }); %>

tinyMCE4 can't get external templates to work

I'm very new to tinyMCE (and to JavaScript), so I'm sorry if the answer to my question is obvious. (I'm also working on code and files that another developer created and that I'm not overly familiar with.)
I need to use an external template file for tinyMCE4, and I can't get it to work. I've looked at the tinyMCE4 documentation, but I don't understand where I'm going wrong.
The tinyMCE init is in an index.cfm file, and the list of templates is in a separate file, template_list.js.
Contents of template_list.js:
var tinyMCETemplateList = [
["Name", "templates/file1.cfm", "Name."],
["Name2", "templates/file2.cfm", "Name2."],
...
];
In index.cfm, I've included "template" in the plugins line.
To pull in the templates to appear as a list in a drop-down so the user can choose a template, I've tried:
template_external_list_url: "tinymce/js/tinymce/template_list.js"
With this, when I run the program and click the Insert Template button I get a "No templates defined" error.
I've also tried:
templates : [{url:"tinymce/js/tinymce/template_list.js"}]
With this, the Insert Template dialog box appears, but the drop-down is empty, and the raw code from template_list.js appears in the text area under the drop-down. I get the same result if I change the code in template_list.js to:
[
{title: "Name", url: "templates/file1.cfm", description: "Name."},
{title: "Name2", url: "templates/file2.cfm", description: "Name2."},
...
]
...and also if I add quotations around "title", "url", and "description".
Again, sorry if the answer is obvious, but as a beginner I appreciate any help.
Per the documentation the TinyMCE configuration object expects you to pass an array containing one object for each template. At a high level it would look like this:
tinymce.init({
selector: "textarea", // change this value according to your HTML
plugins: "template",
menubar: "insert",
toolbar: "template",
templates: [
{title: 'Item 1', description: 'Desc 1', content: 'My content'},
{title: 'Item 2', description: 'Desc 2', url: 'development.html'}
]
});
You will note that the templates configuration option is passed an array of objects - this is what TinyMCE expects so no matter what you have to return an array of objects.
You can insert the template HTML directly (as shown in the first example above) or you can point to a URL that the browser can fetch when TinyMCE is initialized (as shown in the second example above). There is no template_external_list_url configuration option so that is not working because its not valid.
If you want to externalize the templates outside the TinyMCE configuration you can place the data in a file and reference that via a URL. For example:
tinymce.init({
selector: "textarea", // change this value according to your HTML
plugins: "template",
menubar: "insert",
toolbar: "template",
templates: "/path/to/the/file/templates.php"
});
The URL referenced there must return an array of objects as that is ultimately what TinyMCE is expecting. Your example above seems to imply your external file is returning a JavaScript variable named tinyMCETemplateList - but that means nothing to TinyMCE so while the file may be loaded what is "returned" is not an array of JavaScript objects.
I would suggest you start by getting things to work without externalizing the templates (just make sure you get the basics working). Then externalize the content to a separate file and make sure that the file returns an array of objects. I would note that your example using tinyMCETemplateList seems to return an array of arrays which is not what TinyMCE is expecting.
I found this really frustrating and fiddly to get working at all. Eventually what I'm doing is calling a function in another js file that returns an array that I give to the templates parameter.
function GetTemplateArray()
{
return new Array(
{
title: "2 Columns",
url: "templates/template1.html",
description: "Adds a 2 column table"
},
{
title: "3 Columns",
url: "templates/scf/template2.html",
description: "Adds a 3 column table"
}
);
}
Then in the tinymce.init code:
tinymce.init(
{
...
templates: GetTemplateArray(),
...

Displaying data from two collections using each block

So I have 2 collections as follows
Collection user, a document might look like this
{_"id":"xyz",
"name":"sam"
}
Collection items, more that one documents linked to user collection as follows
{_"id":"123345",
"userid":"xyz"
"item":"potato"
}
{_"id":"3456",
"userid":"xyz"
"item":"tomato"
}
now lets say i am running a query to display all documents with name sam as follows, (will be run as a helper)
return User.find({name:"sam"});
and I pass the records into blaze template and display value using {{#each}}.
Now, additionally I want to also display data from collection "items" along with collection "users". So my data in html after using {{#each}} might look like this
<li> sam ...potato, tomato </li>
<li> sam ...potato, tomato, orange </li>
<li> sam ...pineapple </li>
<li> sam ... </li>
i.e data is being displayed on the template using #each but from 2 different collections.
Can anyone tell me how the code in my template should look like?
You can use publish-composite package when you make your users publication. (See example 1 in the link)
So for your use case something like should work:
Meteor.publishComposite('userItems', {
find: function() {
return Users.find({
name: "sam"
},
{
sort: {
...
},
fields: {
...
}
});
},
children: [{
find: function(user) {
return Items.find({
userid: user._id
}, {
fields: {
"item": true,
...
}
});
}}]
});
The solution here is to pass a parameter to the helper. Here it should happen a little bit trickier:
1)Know how to pass parameters:
lets name the helper products
HTML
{{products paramA}}
JS
products: function(userId){
findOne({userId:userId})
}
2)Perfect, but how to pass the _id:
As you are calling the users helper with each you have access by {{_id}} so it should be possible to pass it.
If this somehow does not work. Again try to use the each. Try to reach the element in the products helper by this._id.
I hope the two ways will be enough to solve your problem.

Add JavaScript code dynamically with JSON in Asp.net - JVector Map

I am using JVector map and marking some locations on the map using Markers.
According to the documentaiton the following code can be used to mark locations.
markers: [
{ latLng: [53.3574436, 9.9076650], name: 'some city' },
{ latLng: [53.3574436, 10.2127204], name: 'another city' },
{ latLng: [56.5611120, 24.0300030], name: 'one more city' }
]
In my case I am not sure how many locations I need to mark. Some times 3, some times 5. So what I want to know is, it is possible to Generate the code inside markers : [ ] dynamically with JSON. Or may be any other way?
You could add code with ClientScriptManager.RegisterClientScriptBlock
See: https://msdn.microsoft.com/en-us/library/system.web.ui.clientscriptmanager.registerclientscriptblock(v=vs.140).aspx
Or you could do it inline in the markup with <% %> tags.

Multilingual in Meteor

I'm developing a multilingual app in Meteor.js
I would like to know about best way in your opinion to do that; as example here is wat I'm doing right now (pretty sure that can be done better);
First I save items in mongodb with properties neted in a language root:
{
en: {
name: "english name",
content: "english content"
},
it: {
name: "italian name",
content: "italian content"
},
//since images are the same for both, are not nested
images: {
mainImage: "dataURL",
mainThumb: "dataURL"
}
}
Then I publish a subscription using currentLang session variable:
Meteor.publish("elementsCurrentLang", function(currentLang) {
var projection = {
images: 1
};
projection[currentLang] = 1;
return Elements.find({}, projection);
});
I subscribe on route using Iron Router waitOn hook:
Router.route('/eng/elements', {
waitOn: function() {
return Meteor.subscribe("municipalitiesCurrentLang", Session.get('currentLang'));
},
action: function() {
this.layout('ApplicationLayout');
this.render('elements');
}
});
Now the first problem: I would like to reuse the same template for every language, but I can't simply put in the template {{name}} or {{content}} since the subscription returns the attributes nested under lang root, so it is needed to do for example {{en.name}} for english or {{it.name}} for italian;
To avoid this I use a template helper that buids a new object; essentially it removes attributes from the lang root:
Template.elements.helpers({
elements: function() {
var elements = Elements.find();
var currentLang = Session.get('currentLang');
var resultList = [];
elements.forEach(function(element, index) {
var element = {
name: element[currentLang].name,
content: element[currentLang].nameUrl,
images: element.images
};
resultList.push(element);
});
return resultList;
}
});
And now in the template I can access attributes like wanted:
<h1>{{name}}</h1>
<p>{{content}}</p>
Before continuing with this approach I want to listen for suggestions, since I don't know if this will work well; when Session.currentLang will change, the subscription will be reloaded?
is there a way to avoid the forEach loop in template helpers?
I'm developping a multilangage web app too and I advise you to use a package, like this one : https://atmospherejs.com/tap/i18n
You can change the langage reactively. Have the same template for all your langages, as you want !
You can put it as a parameter in the route.
Personnaly I use it as a Session variable and in the user profile !
If you use this package, you also can export your app, or part of it, more easily as many developpers will use the same code.
you put all your words in json files :
en.i18n.json:
{
"hello": "hello"
}
fr.i18n.json:
{
"hello": "bonjour"
}
and
{{_ "hello" }}
will write hello or bonjour depending of the langage set. You can set it with :
TAPi18n.setLanguage(getUserLanguage())
//getUserLanguage() <- my function to get the current langage in the user profile or
the one used by the navigator
This module does what you're looking for
https://github.com/TAPevents/tap-i18n-db
As the developer says: "Extends the tap:i18n package to allow the translation of collections."
Finally there is a package which is very complete (it also works with number formats, locales...) and is being updated frequently.
https://github.com/vazco/meteor-universe-i18n
You can also install https://atmospherejs.com/universe/i18n-blaze for using it with blade.
Just name your files with the pattern locale.i80n.json and its contents like
{
name: "english name",
content: "english content"
}
then translate your strings with {{__ 'name'}}.

Resources