How to define messages with react-i18next - react-i18next

I'd like to ask a question about whether react-i18next provides us a way to define messages as react-intl
I wanna define all my messages first then using i18next-scanner to extract to json file.
Thanks in advance for your help in this matter.

After a while of researching. I'd give my way to someone wanna define messages in such a messages.js. BTW, I'm using i18nxt-scanner to extract the messages to JSON file.
i18next-scanner.config.js
module.exports = {
input: [
'src/app/**/*.{js,jsx}',
// Use ! to filter out files or directories
'!app/**/*.spec.{js,jsx}',
'!app/i18n/**',
'!**/node_modules/**',
],
output: './',
options: {
debug: true,
removeUnusedKeys: true,
func: {
list: ['getTranslationId'],
extensions: ['.js', '.tsx'],
},
lngs: ['en', 'ko'],
ns: ['translation'],
defaultLng: 'en',
defaultNs: 'translation',
defaultValue: '',
resource: {
loadPath: 'src/locales/{{lng}}/{{ns}}.json',
savePath: 'src/locales/{{lng}}/{{ns}}.json',
jsonIndent: 2,
lineEnding: '\n',
},
nsSeparator: false, // namespace separator
keySeparator: false, // key separator
interpolation: {
prefix: '{{',
suffix: '}}',
},
},
};
messages.js
import { getTranslationId } from 'locales/utils';
const messages = {
title: getTranslationId('Homepage_title', {
defaultValue: 'hello, {{name}}',
}),
count: getTranslationId('Homepage_count', {
defaultValue: '{{count}} time',
count: 0, // for plurals
}),
};
export default messages;
locales/utils.js
export const getTranslationId = id => {
if (!id || !id.includes('_'))
throw new Error('ID pattern should be "BLOCK_ElEMENT"');
return id;
};
Extracting command
yarn run i18next-scanner
Hope this helps! :D

Related

Can rollup-plugins access the AST created by previous plugins in the plugin chain?

We use multiple rollup-plugins that parse their input to an AST. As they run on the same files, each file is parsed multiple times. Can this be optimized, so that each file is parsed only once? Minimal example:
// rollup.config.js
import {createFilter} from '#rollup/pluginutils';
import {simple} from 'acorn-walk';
import {attachComments} from 'astravel';
import {generate} from 'astring';
export default {
input: 'src/main.js',
output: {file: 'bundle.js', format: 'cjs'},
plugins: [{
name: 'plugin1',
transform(code, id) {
const comments = [];
const ast = this.parse(code, {onComment: comments});
attachComments(ast, comments);
simple(ast, {
Identifier(n) {
// rewrite wrong to right
if (n.name === 'wrong') n.name = 'right';
}
});
return {
code: generate(ast, {comments: true}),
ast,
map: null /* minimal example, won't create a source map here */
};
}
}, {
name: 'plugin2',
transform(code, id) {
const comments = [];
const ast = this.parse(code, {onComment: comments});
attachComments(ast, comments);
simple(ast, {
CallExpression(n) {
// rewrite mylog(...) to console.log(...)
if (n.callee.type === 'Identifier' && n.callee.name === 'mylog') {
n.callee = {
type: 'MemberExpression',
object: {type: 'Identifier', name: 'console', start: n.start, end: n.end},
property: {type: 'Identifier', name: 'log', start: n.start, end: n.end},
computed: false,
start: n.start,
end: n.end
}
}
}
});
return {
code: generate(ast, {comments: true}),
ast,
map: null /* minimal example, won't create a source map here */
};
}
}]
};
Now I understand that transform() can return an AST, so that parsing doesn't have to happen twice. And I understand that this.parse() uses the rollup-internal acorn instance. My simple mind thought that this.parse() could return the AST created by previous transform() calls, if available. But I assume that all sorts of demons await on that road, e.g. when this.parse() was called with different options.
Is there a different way achieve what I described? A different hook maybe?
I would love to not have all plugins in one and switching them on and off via options (I see that this would be a solution, but a really cumbersome one).

Send Signed Transaction for Contract Interaction on Quorum using web3js

I am currently running the 7 nodes example given in quorum-examples github repo. I have deployed a very simple storage contract which gets and sets the value. As per the example, I am able to interact with the smart contract inside the geth node cmd line. However I would like to interact with it using another address outside the node and so I wrote the following code:
const Web3 = require('web3')
const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:22000'))
const { Transaction } = require('#ethereumjs/tx')
const { default: Common } = require('#ethereumjs/common')
const run = async () => {
const contractInstance = await new web3.eth.Contract(
[
{
constant: true,
inputs: [],
name: 'storedData',
outputs: [{ name: '', type: 'uint256' }],
payable: false,
type: 'function',
},
{
constant: false,
inputs: [{ name: 'x', type: 'uint256' }],
name: 'set',
outputs: [],
payable: false,
type: 'function',
},
{
constant: true,
inputs: [],
name: 'get',
outputs: [{ name: 'retVal', type: 'uint256' }],
payable: false,
type: 'function',
},
{
inputs: [{ name: 'initVal', type: 'uint256' }],
payable: false,
type: 'constructor',
},
],
'0xd9d64b7dc034fafdba5dc2902875a67b5d586420'
)
const customCommon = Common.forCustomChain('mainnet', {
chainId: 10,
})
const txCount = await web3.eth.getTransactionCount(
'ed9d02e382b34818e88b88a309c7fe71e65f419d'
)
const txData = {
nonce: web3.utils.toHex(txCount),
gasLimit: '0x47b760',
gasPrice: '0x00',
value: '0x0',
chainId: 10,
to: '0xd9d64b7dc034fafdba5dc2902875a67b5d586420',
data: contractInstance.methods.set(10).encodeABI(),
}
const tx = Transaction.fromTxData(txData, { common: customCommon })
const signedTx = tx.sign(
Buffer.from(
'e6181caaffff94a09d7e332fc8da9884d99902c7874eb74354bdcadf411929f1',
'hex'
)
)
const serializedTx = signedTx.serialize()
const result = await web3.eth.sendSignedTransaction(
`0x${serializedTx.toString('hex')}`
)
return result
}
run().then(console.log).catch(console.log)
However whenever I try to send the transtion, it always errors out to
"Transaction has been reverted by the EVM:\n{\n \"blockHash\": \"0xd6b06321882912185f5e1d3401a012f58b6bbf7eee1e1d2c6c2cd80a0e13bbdc\",\n \"blockNumber\": 5,\n \"contractAddress\": null,\n \"cumulativeGasUsed\": 23751,\n \"from\": \"0x0fbdc686b912d7722dc86510934589e0aaf3b55a\",\n \"gasUsed\": 23751,\n \"logs\": [],\n \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\n \"status\": false,\n \"to\": \"0x9d13c6d3afe1721beef56b55d303b09e021e27ab\",\n \"transactionHash\": \"0x8c7fd175ab037e24e531804774e8b89bf5aea25de8d99aa9bc2c034229603299\",\n \"transactionIndex\": 0\n}",
Do let me know if more info is required and I will update the post.
The smartcontract code is as follows:
pragma solidity ^0.5.0;
contract simplestorage {
uint public storedData;
constructor(uint initVal) public {
storedData = initVal;
}
function set(uint x) public {
storedData = x;
}
function get() view public returns (uint retVal) {
return storedData;
}
}
I think i met the similar issue as well. My issue was invalid chain id signer. I checked many docs and tried to set the custom chain id which was what you did about "common". But nothing changed until i changed the version of ethereumjs-tx to ^1.3.7. btw you dont need common if you try my solution.

Vue.js - Element UI - HTML message in MessageBox

I'm using vue-js 2.3 and element-ui. This question is more specific to the MessageBox component for which you can find the documentation here
Problem
I'd like to be able to enter html message in the MessageBox
More specifically I would like to display the data contained in dataForMessage by using a v-for loop.
Apparently, we can insert vnode in the message but I have no idea where to find some information about the syntax.
https://jsfiddle.net/7ugahcfz/
var Main = {
data:function () {
return {
dataForMessage: [
{
name:'Paul',
gender:'Male',
},
{
name:'Anna',
gender:'Female',
},
],
}
},
methods: {
open() {
const h = this.$createElement;
this.$msgbox({
title: 'Message',
message: h('p', null, [
h('span', null, 'Message can be '),
h('i', { style: 'color: teal' }, 'VNode '),
h('span', null, 'but I would like to see the data from '),
h('i', { style: 'color: teal' }, 'dataForMessage'),
])
}).then(action => {
});
},
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
I think this is what you want.
methods: {
open() {
const h = this.$createElement;
let people = this.dataForMessage.map(p => h('li', `${p.name} ${p.gender}`))
const message = h('div', null, [
h('h1', "Model wished"),
h('div', "The data contained in dataForMessage are:"),
h('ul', people)
])
this.$msgbox({
title: 'Message',
message
}).then(action => {
});
},
}
Example.
You can also use html directly and convert to vnodes by using domProps:
const html = '<div><h1>Model wished</h1><div>The data contained in dataForMessage are:</div><ul><li>Paul Male</li><li>Anna Female</li></ul></div>'
const message = h("div", {domProps:{innerHTML: html}})
(The above is simplified without the loop. Just to get the idea)
Fiddle

Keystone.js filtering on related fields within own model

I am working on filtering my subsection selection to display only subSections that are related to the current mainNavigationSection. Each of these subsections also has a mainNavigation section. For some reason the current implementation is not returning any results.
Here is my Page Model:
Page.add({
name: { type: String, required: true },
mainNavigationSection: { type: Types.Relationship, ref: 'NavItem', refPath: 'key', many: true, index: true },
subSection: { type: Types.Relationship, ref: 'SubSection', filters: { mainNavigationSection:':mainNavigationSection' }, many: true, index: true, note: 'lorem ipsum' },
state: { type: Types.Select, options: 'draft, published, archived', default: 'draft', index: true },
author: { type: Types.Relationship, ref: 'User', index: true }
}
Here is my subSectionModel:
SubSection.add({
name: { type: String, required: true, index: true },
mainNavigationSection: { type: Types.Relationship, ref: 'NavItem', many: true, required: true, initial: true},
showInFooterNav: { type: Boolean, default: false },
defaultPage: { type: Types.Relationship, ref: 'Page' },
description: { type: Types.Html, wysiwyg: true, height: 150, hint: 'optional description' }
});
From what it seems, you have the possibility of many mainNavigationSections on your model. You'd have to iterate over each of them on the current Page, and find the related SubSections. You'll need to use the async Node module to run all the queries and get the results from each.
var async = require('async');
var pID = req.params.pid; // Or however you are identifying the current page
keystone.list('Page').model.findOne({page: pID}).exec(function (err, page) {
if (page && !err) {
async.each(page.mainNavigationSection, function (curMainNavigationSection, cb) {
keystone.list('SubSection').model
.find({mainNavigationSection: curMainNavigationSection._id.toString()})
.exec(function (err2, curSubSections) {
if (curSubSections.length !== 0 && !err2) {
// Do what you need to do with the navigation subSections here
// I recommend using a local variable, which will persist through
// every iteration of this loop and into the callback function in order
// to persist data
return cb(null)
}
else {
return cb(err || "An unexpected error occurred.");
}
});
}, function (err) {
if (!err) {
return next(); // Or do whatever
}
else {
// Handle error
}
});
}
else {
// There were no pages or you have an error loading them
}
});

i18next - All languages in one .json file

How can I make i18next load all languages from just one file?
I managed to do it by putting each language in a seperate file (translation-en.json, translation-no.json, etc), and also managed to input languages with the resStore option, but putting it all in a seperate .json file is really not documented anywhere (I've searched for 4 hours+ now)
My js code:
i18n.init({
debug: true,
lng: 'en',
resGetPath: 'translation.json'
},
function(t) {
console.log(t('test'));
});
My translation.json file:
{
en: {
translation: {
test: "some string"
}
},
no: {
translation: {
test: "litt tekst"
}
}
}
Ok, so I managed to "hack" it byt putting an object into a seperate .js file, include it in a script tag and loading it using resStore, but that just can't be the best way to use this lib.
Assume that your translation.json has loaded and assigned to a variable named resStore:
var resStore = {
en: {
translation: {
test: "some string"
}
},
no: {
translation: {
test: "litt tekst"
}
}
};
Next, you can override default ajax loading functionality with your customLoad function. An example might look like this:
var options = {
lng: 'en',
load: 'current',
lowerCaseLng: true,
fallbackLng: false,
resGetPath: 'i18n/__lng__/__ns__.json',
customLoad: function(lng, ns, options, loadComplete) {
var data = resStore[lng][ns];
loadComplete(null, data); // or loadComplete('some error'); if failed
},
ns: {
namespaces: ['translation'],
defaultNs: 'translation'
}
};
i18n.init(options, function(t) {
t('test'); // will get "some string"
});
new update on Mar 20, 2015
You can simply pass your resource store with the resStore option:
i18n.init({ resStore: resources });