Localization in Polymer? - localization

I'm going to create a webapp with Polymer. For that webapp I need localization. Is there a Polymer way to do localization?
Has anyone ever done localization in a Polymer webapp?

I18n and l10n are also on my to-do list. Currently i'm porting an app from AngularJS to Polymer. The back-end is Ruby on Rails. I use the i18n-js gem which converts the Rails translation files (en.yml, de.yml and so on) into one big JavaScript file containing an I18n object with all the translations. This gem also provides a JavaScript library for performing text translations and value localizations. But there are other JavaScript libraries providing a similar functionality.
The current locale is set from the response of a HTTP request, returning the users Accept-Language header.
Nothing Polymer specific up to this point.
I then created a bunch of global Polymer expression filters that perform the various locale transformations on their input strings. This is the same method as the one that i've learned to use in an AngularJS application. The translation filter looks like follows (I18n.t is the translation function of the JavaScript library)
PolymerExpressions.prototype.i18n = function(key) {
return I18n.t(key);
};
and is used like so
<paper-button label="{{ 'action.help' | i18n }}"></paper-button>
A date localization may be written as
{{ someDate | i18n_date('short') }}
I packaged the i18n filters and additional helper functions into a Polymer element, so I can also include this element in another element and use the translation functions from within it's JavaScript code.
The i18n element is also include in my main app element where it initializes the I18n library and sets the default and current locale.

Use Polymer.AppLocalizeBehavior
https://github.com/PolymerElements/app-localize-behavior
I am using this behavior in PWA Template for locales per custom element.
https://github.com/StartPolymer/progressive-web-app-template

Not being aware of a Polymer-way doing i18n, I suggest doing that server-side.
In case the framework is Spring, I would implement the custom elements as jsp, and handle the i18n as usual with the <spring:message /> tags.
Only caveat is that switching the language of the application would require a complete reload. But as language switching is usually not done often, I don't think of this as a problem.

For Polymer 1.0 I just published a simple (heavily in development) element (see it on gitlab or read about it here). It loads the translation files asynchronously and the usage is fairly simple:
<!-- Import it in head -->
<link rel="import" href="bower_components/quaintous-i18n/quaintous-i18n.html">
<!-- initialize it in body -->
<quaintous-i18n locales-path="/locales/fa.json"></quaintous-i18n>
Now you can use it in various ways:
In computed properties: just add I18N as your element behavior and translate your data bindings, e.g. {{__('hello')}}
In global context just use I18N object, e.g. I18N.__('hello')

I implemented a different way of doing it even though there is AppLocalizeBehavior which seem to do it pretty well. I created a locale.json file with a list of languages, name of the page for which data was needed and then the data to be displayed.
{
"en": {
"loginPage" : {
"login" : "Log in",
"loginUserid" : "Enter user id",
"loginPassword" : "Enter password"
},
},
"nl": {
"loginPage" : {
"login" : "Log in",
"loginUserid" : "Voer gebruikers-ID in",
"loginPassword" : "Voer wachtwoord in"
},
},
}
I created a translate component which has the responsibility of setting the language in the local-storage (though it needs a bit of refactoring and I could use navigator object for getting the language) as well as get data from the locale.json. This looked like this:
class Translate extends
Polymer.mixinBehaviors([Polymer.AppLocalizeBehavior], Polymer.Element) {
static get is() { return 'translate'; }
static get properties() {
return {
language: {
type: String,
value: 'nl',
notify: true
},
resources: {
type: Object,
notify: true
}
}
}
ready() {
super.ready();
if (localStorage.length) {
if (localStorage.getItem('language')) {
this.language = localStorage.getItem('language');
}
else {
localStorage.setItem('language', this.language);
}
} else {
localStorage.setItem('language', this.language);
}
}
attached() {
this.loadResources(this.resolveUrl('locales.json'));
}
}
window.customElements.define(Translate.is, Translate);
Now you can utilize this custom element inside your root or app shell of the application
<translate
class="translate"
language="{{language}}"
resources="{{resources}}">
</translate>
Put an observer on your resources property and get the data from your locale.json. Now based on different pages pass only the translation values which are needed for that page. page-values being the values of the translation strings like this:
<login-form
title='Login'
name="login"
page-values="[[pageValues.loginPage]]"
login-success="[[_loginSuccess]]"
api={{apiCollection.login}}></login-form>
Hope this helps.

I created an implementation on my own. Looking what I made it's not that difficult to do.

Related

How to change the slug in the url based on the language selected using gatsby-theme-i18n-react-i18next?

I have a project that uses Gatsby and for localization, I have used gatsby-plugin-react-i18next plugin. How can I change the slug in the URL based on the language selected. For example, I have a page named product.js under the pages folder. In French language, I want the page as https://www.example.com/fr/produit instead of https://www.example.com/product.
You have a bunch of options available using the gatsby-plugin-react-i18next plugin. In your case, language holds the currently selected language.
You have (at least) two options:
Using the exposed Link component from gatsby-plugin-react-i18next:
import {Link} from 'gatsby-plugin-react-i18next';
const SpanishAboutLink = () => {
const {language} = useI18next();
<Link to="/about" language={language}>
About page in Spanish
</Link>
};
The plugin wraps the Link component from Gatsby adding a custom prop (language) that can be filled with the exposed state of useI18next hook.
Using the built-in Link (from Gatsby) and using a template literal:
const SpanishAboutLink = () => {
const {language} = useI18next();
<Link to=`{language}/about`>
About page in the selected language
</Link>
};
In this approach, you are getting the current language in the same way as before but you are concatenating it to a Link component to create a URL based on that parameter.
In your case, since you are changing the slug in both pages (product and produit), you'll need to query both using a page query and applying one of the previous approaches dynamically. For example:
import * as React from 'react'
import { graphql } from 'gatsby'
const HomePage = ({data}) => {
const {language} = useI18next();
return (
<div>
<Link to={`${language}/${data.allYourPagesQuery.edges.node[0].slug}`}>
{data.allYourPagesQuery.edges.node[0].title}
</Link>
</div>
)
}
export const query = graphql`
query HomePageQuery {
allYourPagesQuery{
edges {
node {
name
slug
}
}
}
}
`
export default HomePage
Due to the lack of details in your implementation and your data sources, I'm not able to guess how your query should look like. But assuming you have a way of retrieving the title and the slug of your available pages you can do something like the snippet above.

Passing complex information in Angular directives

I am using JQuery UI in an Angular application. I noticed that I was repeating the same pattern for each directive: Call the JQuery UI function with a single complex object for initialization. Rather than write separate directives for each component, I have found it easier to use a stub directive. This may not be a long term solution but it works for now.
Is there a better way to inject the attributes to make the markup more readable while still keeping the generic nature of the directive? Specifically, can I avoid using a JSON string so that it reads more like a normal angular directive.
The existing line:
<button jquiw-control='{"control":"button","options":{"label":"Hello","icons": {"primary": "ui-icon-gear","secondary": "ui-icon-triangle-1-s"}}}' ng-click="jump()"></button>
<button jquiw-control="button" jquiw-button-label="Hello" jquiw-button-icons-primary= "ui-icon-gear" jquiw-button-icons-secondary="ui-icon-triangle-1-s" ng-click="jump()"></button>
Here is a plunk of a working example of my Generic ui directive. http://plnkr.co/edit/eRoOeq
At least you can put the hardcoded JSON in the controller like this
$scope.config = {
"control": "button",
"options": {
"label": "Hello",
"icons": {
"primary": "ui-icon-gear",
"secondary": "ui-icon-triangle-1-s"
}
}
};
and then change the template to
<button jquiw-control='{{config}}' ng-click="jump()"></button>
Plunker: http://plnkr.co/edit/yY1Lc2?p=preview

Multilingual in grails view

i'm working in Multilingual grails application (English and arbaic) , i want when the user chooses Arabic language the view's labels will be on the right side of the page and in English on the left side , how this can be achieved ?
thanks
You can use internationalization in grails through messages.properties file, you can define message signature in files and and they can be accessed through ?lang=es on the URL, you may need to have two files one for english and another for Arabic.
for example define in the messages.properties:
vendor.link.dashboardLink = Vendor Dashboard
and on the GSP page you can access it like:
<g:message code="vendor.link.dashboardLink" />
you can find more about internalization at grails doc have a look at http://grails.org/doc/2.2.1/guide/i18n.html
If the views have differences beyond simple string substitution, I would recommend using a different set of views based on locale:
Example controller code:
import org.springframework.web.servlet.support.RequestContextUtils as RCU
class ExampleController {
final static String englishLanguageCode = new Locale('en').getLanguage()
final static String arabicLanguageCode = new Locale('ar').getLanguage()
def differentViews() {
def currentLocale = RCU.getLocale(request)
switch(currentLocale.language) {
case englishLanguageCode:
render view: 'englishView'
break
case arabicLanguageCode:
render view: 'arabicView'
break
default:
// pick a default view or error page, etc.
}
}
}

How would you auto format hyperlinks using meteor

I am working on a chat room application and would like to auto format hyperlinks so they can be visited without copy/paste.
I found autolink.js and was able to get it to work using a static HTML template but have not been able to get it working with meteor.
Any suggestions?
Edit -
Meteor Version 0.6.1
Chatroom Application - https://github.com/SmashBrando/chatroom
Autolink.js - https://github.com/bryanwoods/autolink-js
(this is not setup as it did not work)
Put this in the helper you want to display the hyperlink. Assuming you've got the autolink.js all set up in your /client/lib folder just use it with your helper
e.g
client js
Template.hello.greeting = function() {
return "This is a link to Google http://google.com".autoLink()
}
and you need to make sure your HTML uses handlebars that can give html output (thats with 3 curly braces either side instead of 2):
html in your template
{{{greeting}}}
This should output
This is a link to Google http://google.com
Using transform to autolink on cursors
When using a handlebars helper that returns a cursor such as Messages.find() in your code you need to transform your collection. So with your code you need to alter the return value:
Template.messages.messages = function () {
return Messages.find({}, { sort: {time: -1}, transform: function(doc) {
if(doc.message) doc.message = doc.message.autoLink()
return doc;
}
});
};
A transform changes the documents in your collection, so in the above each one's message is autoLinked.
You also need to let let handlebars display this as clickable links by altering your handlebars for the HTML to use 3 curly braces to make sure your 's aren't escaped.:
<template name="message">
<p><strong>{{name}}:</strong> {{{message}}}</p>
</template>

Way to organize client-side templates into individual files?

I'm using Handlebars.js, and currently all my templates live inside script tags which live inside .html files housing dozens of other templates, also inside script tags.
<script type="text/template" id="template-1">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-2">
<div>{{variable}}</div>
</script>
<script type="text/template" id="template-3">
<div>{{variable}}</div>
</script>
...
Then I include this file on the server-side as a partial.
This has the following disadvantages:
A bunch of templates are crammed into HTML files.
Finding a given template is tedious.
I'm looking for a better way to organize my templates. I'd like each each template to live in its own file. For example:
/public/views/my_controller/my_action/some_template.html
/public/views/my_controller/my_action/some_other_template.html
/public/views/my_controller/my_other_action/another_template.html
/public/views/my_controller/my_other_action/yet_another_template.html
/public/views/shared/my_shared_template.html
Then at the top of my view, in the backend code, I can include these templates when the page loads, like this:
SomeTemplateLibrary.require(
"/public/views/my_controller/my_action/*",
"/public/views/shared/my_shared_template.html"
)
This would include all templates in /public/views/my_controller/my_action/ and also include /public/views/shared/my_shared_template.html.
My question: Are there any libraries out there that provide this or similar functionality? Or, does anyone have any alternative organizational suggestions?
RequireJS is really good library for AMD style dependency management. You can actually use the 'text' plugin of requireJS to load the template file in to your UI component. Once the template is attached to the DOM, you may use any MVVM, MVC library for bindings OR just use jQuery events for your logic.
I'm the author of BoilerplateJS. BoilerplateJS reference architecture uses requireJS for dependency management. It also provides a reference implementations to show how a self contained UI Components should be created. Self contained in the sense to handle its own view template, code behind, css, localization files, etc.
There is some more information available on the boilerplateJS homepage, under "UI components".
http://boilerplatejs.org/
I ended up using RequireJS, which pretty much let me do this. See http://aaronhardy.com/javascript/javascript-architecture-requirejs-dependency-management/.
I use a template loader that loads the template using ajax the first time it is needed, and caches it locally for future requests. I also use a debug variable to make sure the template is not cached when I am in development:
var template_loader = {
templates_cache : {},
load_template : function load_template (params, callback) {
var template;
if (this.templates_cache[params.url]){
callback(this.templates_cache[params.url]);
}
else{
if (debug){
params.url = params.url + '?t=' + new Date().getTime(), //add timestamp for dev (avoid caching)
console.log('avoid caching url in template loader...');
}
$.ajax({
url: params.url,
success: function(data) {
template = Handlebars.compile(data);
if (params.cache){
this.templates_cache[params.url] = template;
}
callback(template);
}
});
}
}
};
The template is loaded like this:
template_loader.load_template({url: '/templates/mytemplate.handlebars'}, function (template){
var template_data = {}; //get your data
$('#holder').html(template(template_data)); //render
})
there's this handy little jquery plugin I wrote for exactly this purpose.
https://github.com/cultofmetatron/handlebar-helper

Resources