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

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.

Related

How add react-relay component to the storybook?

I am trying create a storybook for my react-realy app, but i don't know how to set mockup data for that component. For simple a component it is ok, because i can use dummy UI component vs Container approach, but i can't use this for nested relay components, for example there is a UserList component, which i want add to storybook, i can split relay fragment part to container and UI part to the component, but what if UserList children are too relay component? I can't split their when they are a part of the composition of UserList?
Is there some solution for add relay components to the storybook?
I created a NPM package called use-relay-mock-environment, which is based on relay-test-utils which allows you to make Storybook stories out of your Relay components.
It allows nesting of Relay components, so you can actually make stories for full pages made out of Relay components. Here's an example:
// MyComponent.stories.(js | jsx | ts | tsx)
import React from 'react';
import { RelayEnvironmentProvider } from 'react-relay';
import createRelayMockEnvironmentHook from 'use-relay-mock-environment';
import MyComponent from './MyComponentQuery';
const useRelayMockEnvironment = createRelayMockEnvironmentHook({
// ...Add global options here (optional)
});
export default {
title: 'MyComponent',
component: MyComponent,
};
export const Default = () => {
const environment = useRelayMockEnvironment({
// ...Add story specific options here (optional)
});
return (
<RelayEnvironmentProvider environment={environment}>
<MyComponent />
</RelayEnvironmentProvider>
);
};
export const Loading = () => {
const environment = useRelayMockEnvironment({
forceLoading: true
});
return (
<RelayEnvironmentProvider environment={environment}>
<MyComponent />
</RelayEnvironmentProvider>
);
};
You can also add <RelayEnvironmentProvider /> as a decorator, but I recommend not doing that if you want to create multiple stories for different states/mock data. In the above example I show 2 stories, the Default one, and a Loading one.
Not only that, it requires minimal coding, where you don't need to add the #relay-test-operation directive to your query, and the mocked data is automatically generated for you using faker.js, allowing you to focus on what matters, which is building great UI.
Feel free to review the source code here if you want to implement something similar: https://github.com/richardguerre/use-relay-mock-environment.
Note: it's still in its early days, so some things might change, but would love some feedback!
I also created relay-butler, which is a CLI that takes in GraphQL fragments and outputs Relay components, including a auto-generated query component that wraps the fragment component, and Storybook stories (the Default and Loading ones by default) that wrap that query component. And literally within minutes, I can create beautiful Relay components that are "documented" within Storybook.
Would also love some feedback for it!

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.

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

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>

Resources