Multilingual in grails view - grails

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.
}
}
}

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.

Localization in Polymer?

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.

Mapping URL in main menu to every page

I am using in my grails 2.3.4 project with spring security and spring securit ui.
I am having scaffolde my domain contact to the view. I have also a .gsp page which is not scarfolded.
My links from my main menue looks like that:
<li>Pricing</li>
<li>Contact</li>
Thats my URLMappings
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
"/private/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
"/"(view:"/index")
"/pricing"(view:"/pricing")
"/private/dashboard"(view:"/private/dashboard")
"/contact/create"(view:"/contact/create")
"500"(view:'/error')
}
}
My problem is when I am using this two links from my mainpage / then everythings works fine. However using them from 5432:localhost/TestApp/pricing I am getting the link 5432:localhost/TestApp/pricing/contact/create
which goes is not available. If I am using <li>Contact</li>, I am going to 5432:localhost/contact/create, which is also not available. How to go to contact/create from every page?
I appreciate your reply!
The simplest and safest approach would be
<li><g:link uri="/contact/create">Contact</g:link></li>
Other attributes on the g:link tag will pass through to the generated a tag, with the exception of id - you need to use elementId instead, as id is treated as a parameter to the link generation (controller/action/id)
<li><g:link uri="/contact/create" class="nav" elementId="contactlink">Contact</g:link></li>
would become
<li>Contact</li>
(where /TestApp is the application context path - if you deploy the app at a different context path then then link will change to match).

How can I load static content into a gsp page?

We have a grails project that is templated to produce two different sites. The sites have two different Frequently Asked Question pages but we would like to keep the template the same. We were thinking about including two different *.groovy files that have variables in them with the questions and then map those variables to a gsp page. Or maybe two different *.gsp files and the right one gets included at startup.
What is the best way to include the static content into the gsp page while reusing as much code as possible and how would I go about doing it?
Let me know if you need more information.
Grails have the concept of templates to reuse your view code. For example:
*grails-app/views/book/_bookTemplate.gsp*
<div class="book" id="${book?.id}">
<div>Title: ${book?.title}</div>
<div>Author: ${book?.author?.name}</div>
</div>
grails-app/views/book/someView.gsp
<g:render template="bookTemplate" model="[book: myBook]" />
grails-app/views/book/anotherView.gsp
<g:render template="bookTemplate" model="[book: myBook]" />
So you can use the render tag in any GSP that needs to use your template.
It is kind of late but I was looking for the answer myself. While there is no direct way to have insert static file in Grails, there are various ways you could accomplish so. From controller to custom tag. There is a code for custom tag:
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class HtmlTagLib {
// to be used in gsp like <html:render file="WEB-INF/some-static-file.txt"/>
// file param is relative to web-app folder
static namespace = 'html'
private static final Logger log = LoggerFactory.getLogger(HtmlTagLib .class)
def render = { attrs ->
String filePath = attrs.file
if (!filePath) {
log.error("'file' attribute must be provided")
return
}
String applicationPath = request.getSession().getServletContext().getRealPath( filePath )
def htmlContent = new File(applicationPath).text
out << htmlContent
}
}
Credits to Dónal on Rendering HTML files in Grails

grails current page highlight

In grails I have a menu. I'm trying to highlight the menu item for the active page:
link1
link2 (show as bold if the controller action partially matches this gsp name)
link3
I have working code but it seems like there would be a better way.
Taglib works fine:
def active = { attrs, body ->
for (page in attrs.check) {
if (params.action.startsWith(page)) {
out << "current"
break
}
}
}
This option works fine, but seems wordy:
<li>Contact Info</li>
<li>About You</li>
This blows up:
<g:link action='myProfile' class="${<xyz:active check='${['myControllerAction']}'/>}">My Profile</g:link>
I don't believe you can pass a taglib as a parameter to g:link
I also have the requirement that multiple gsps/actions would cause a link to be active because of how they are named:
aboutYouLocation
aboutYouBackground
aboutYouEducation
all make this link the active one:
About You
I can do a partial match, but I've also got some actions/gsps that begin with aboutYour (extra R) resulting in my use of the array being passed into my taglib.
There's a standard way of doing that with the Platform Core plugin. It will provide you a Navigation API:
grails-app/conf/AppNavigation.groovy
navigation = {
// Declare the "app" scope, used by default in tags
app {
contact(action: 'contactInfo')
about(action: 'aboutYouFamily')
}
}
*grails-app/view/_menu.gsp* (template that you can use in your layout or GSP's)
<nav:menu scope="app" id="navigation" />
You can also customize the html generated for your menu, check the custom item rendering.

Resources