i18next with axios backend in react - i18next

I'm trying to implement language change in my app using these dependencies:
"i18next": "^21.6.13",
"i18next-browser-languagedetector": "^6.1.3",
"i18next-http-backend": "^1.3.2",
"react-i18next": "^11.15.6",
I tried pretty standard method and it works fine:
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { DateTime } from "luxon";
import Backend from "i18next-http-backend";
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
debug: true,
fallbackLng: "en",
interpolation: {
escapeValue: false,
format: (value, format, lng) => {
if (value instanceof Date) {
return DateTime.fromJSDate(value)
.setLocale(lng)
.toLocaleString(DateTime[format]);
}
return value;
},
},
});
export default i18n;
What i need to do is to get translations from backend with axios. I tried to do this https://github.com/i18next/i18next-http-backend , but all examples are with local json data and this is not what i want to do. I tried to hook data and pass it in resources, but it dosen't work. Any thoughts of how it could be done? Or helpful links? It doesn't have to be with axios. What i have is accessive link with json data and I want to use it as backend with i18next. Any help would be much appreciated, thanks.
P.S. please don't ban if question is not clear enough, I'll try to explain better if needed. I'm tired.

Related

How to get access to Vue.prototype in asyncData?

In plugin, I add new property to Vue prototype.
import Vue from 'vue';
import { DateTime } from 'luxon';
Object.defineProperty(Vue.prototype, '$DateTime', { value: DateTime });
I want to use it in asyncData, how to get access?
async asyncData(context) {
context.store.commit('calendar/setSelectDate', $DateTime.now());
}
I'm not sure that defineProperty is the way to go here. You could maybe inspect the Vue instance itself and see if there is some $DateTime on it, if it is, a context.$DateTime should do the trick.
If it's not working with context.$DateTime, maybe try it when your component is mounted in a regular this.$DateTime on a button click, for debugging purposes.
Using regular Nuxt plugins or even inject is a more clean and Vue-y way of doing things.
import { DateTime } from 'luxon'
export default ({ app }, inject) => {
inject('DateTime', DateTime)
}
then
async asyncData({ store, $DateTime }) {
store.commit('calendar/setSelectDate', $DateTime.now())
}
or from components/pages
this.$DateTime.now()
Speaking of Vue, you don't want to use vue-luxon. Looks like a simple and quick way of using the library. Is it because it is not mantained for already 7 months or something else?
import Vue from 'vue';
async asyncData(context) {
context.store.commit('calendar/setSelectDate', Vue.prototype.$DateTime.now());
}

How to make a dynamic import in Nuxt?

In my nuxt component I want to use the ace editor:
import Ace from "ace-builds/src-noconflict/ace"
when the component is mounted I am doing the following:
this.editor = Ace.edit...
Obviously the window is not defined on the server on page reload. But unfortunately I just can't find a solution to fix this issue.
Is there a way to import a package on the mounted() hook?
I already tried
const Ace = require("ace-builds/src-noconflict/ace")
But that doesn't quite seem to work. Do you have any ideas to solve this issue?
I already tried to register a plugin plugins/ace.js:
import Vue from "vue"
import Ace from "ace-builds/src-noconflict/ace"
Vue.use(Ace)
registered it in nuxt.config.js:
plugins: [
{ src: "~/plugins/ace", mode: "client" }
],
But how do I use Ace in my component now? It is still undefined...
Since the error was thrown during the import statement, I'd recommended using dynamic imports as explained in my other answer here.
async mounted() {
if (process.client) {
const Ace = await import('ace-builds/src-noconflict/ace')
Ace.edit...
}
},
From the official documentation: https://nuxtjs.org/docs/2.x/internals-glossary/context
EDIT: I'm not sure about Ace and it's maybe a drastic change but you may also give a look to vue-monaco which is elbow-to-elbow popularity wise (vanilla Monaco editor).
EDIT2: mounted actually only runs on the client so you could strip the process.client conditional. Meanwhile, I do let it here in case you want to run some logic in other hooks like created (which are run on both server + client). More info here.
EDIT3: not directly related to the question, but some packages expose a component which is only available on the client-side (no SSR support), in those cases you could import the component only on the client side and easily prevent any other errors.
Nuxt Plugin
IMHO you were on the right track with the "plugin" solution. Only mistake was the
Vue.use(Ace) part. This only works for vue plugins.
The plugin file could look somewhat like that:
import Ace from 'ace-builds/src-noconflict/ace'
import Theme from 'ace-builds/src-noconflict/theme-monokai'
export default ({ app }, inject) => {
inject('ace', {
editor: Ace,
theme: Theme
})
}
Then you could use this plugin and initiate the editor in a component this way:
<template>
<div id="editor">
function foo(items) {
var x = "All this is syntax highlighted";
return x;
}
</div>
</template>
<script>
export default {
data () {
return {
editor: {}
}
},
mounted () {
this.editor = this.$ace.editor.edit('editor')
this.editor.setTheme(this.$ace.theme)
}
}
</script>

vuejs with electron, can't use fs

I'm using Vue with it's Electron plugin and I want to use fs to read directories, but it gives me this error. What could be the problem?
TypeError: Object(...) is not a function
import Vue from 'vue';
import Component from 'vue-class-component';
import { readdir } from 'fs';
#Component
export default class Directory {
mounted() {
readdir('C:/', (err, files) => {
if (err) console.log(err);
console.log(files)
})
}
}
I only worked with Angular+Electron combo, but with that I used electron's main process to do file manipulation stuff.
Further read: https://www.electronjs.org/docs/api/ipc-main
In the main process, you can access "fs" easily like you would in node.
I don't know if this is the case with Vue, but maybe this helps.

Nuxt - define a const once and which can use across all pages

I'm trying to implement Shopify JS SDK in Nuxt
So this is what I did, a plugin
// plugins/shopify.js
import Vue from 'vue'
import 'isomorphic-fetch'
import Shopify from 'shopify-buy'
export default ({ app }, inject) => {
app.shopify = Shopify.buildClient({
domain: 'aaa.myshopify.com',
storefrontAccessToken: 'aaa'
});
}
nuxt config
//nuxt.config.js
plugins : [{ src : '~/plugins/shopify', ssr: false}]
vendor : ['shopify-buy']
index
asyncData ({ app }) {
return app.shopify.product.fetchAll().then((products) => {
// Do something with the products
console.log(products);
return { products : products }
});
}
The result is
TypeError Cannot read property 'product' of undefined
But it works if I removed the asyncData, refresh my page, and add the code back without refreshing.
I believe this has something to do with the lifecycle.
Can anyone please tell me if I'm doing it the right way, or there's other proper way to define such const which can be use across pages, components etc
And if this is the right way, what I did wrong?
Thanks in advance.
My reference are Nuxt guides as well as examples.
I tried google around but can't locate what I need, or maybe I just didn't get the right keywords.
FROM DOCUMENTATION
Nuxt.js lets you create environment variables that will be shared for
the client and server-side.
To do this, you can use the env property:
nuxt.config.js:
module.exports = {
env: {
baseUrl: process.env.BASE_URL || 'http://localhost:3000'
}
}
Then to access it from anywhere, just use it like so:
process.env.baseEnv
For example, in an axios plugin:
import axios from 'axios'
export default axios.create({
baseURL: process.env.baseUrl
})

Big Locale DBs in React-native (Expo)

I've found this good and simple article https://medium.com/#jamuhl/translate-your-expo-io-react-native-mobile-application-aa220b2362d2 to implement localization in RN (in Expo).
My use case is a bit different: my app have list of hundrends of terms to translate (a js object of ~1MB each language, times 6-7 languages).
The app is totally offline (no chance to load the locale files from a server) so I'm searching the best way to lazy-loads the json/js locale object I want.
I'm here to take advices from RN/i18next experts possibly.
EDIT:
I pretty much copied the i18n configuration of this https://github.com/i18next/react-i18next/blob/master/example/react-native-expo/js/i18n.js
The real databases are in the field data:DB. Obiouvsly that's not the best way to load heavy files, I always loads all the DB of all the languages..can I keep somehow the same simple structure but lazy-load just the language I need?
Otherwise, there is an example of local lazy-load (from the device file system) in i18next and react-native?
import i18n from 'i18next';
import {reactI18nextModule} from 'react-i18next';
i18n
.use(languageDetector)
.use(reactI18nextModule)
.init({
fallbackLng: 'en',
resources: {
en: {
home: {
title: 'Welcome',
introduction: 'This text comes from i18next and is provided in english.',
},
data: { DB:require("./locales/it.json") },
},
de: {
home: {
title: 'Willkommen',
introduction: 'Dieser Text ist von i18next und ist in deutsch.',
},
data: { DB:require("./locales/de.json") },
}
},
// have a common namespace used around the full app
ns: ['common'],
defaultNS: 'home',
debug: true,
interpolation: {
escapeValue: false, // not needed for react as it does escape per default to prevent xss!
}
});
With i18next it's rather simple to create a own backend implementation...https://www.i18next.com/misc/creating-own-plugins#backend
I would suggest bundling your translations with the application and not loading from any external resource. You also can directly add translations on the fly using https://www.i18next.com/overview/api#resource-handling