Comments (27)
You will need a helpers around or library. The main use case of our library is web UI and desktop apps. So you will need to a helper to simplify API a little.
Another problem is that we need a translation in default locale described in your code (not in JSON). We use it to get types. Also to avoid changing all translation when you fix a typo in English translation.
Tomorrow I will write an example.
from i18n.
// lib/i18n.js
import { atom } from 'nanostores'
import { createI18n } from '@nanostores/i18n'
import { readFile } from 'fs/promises'
export const locale = atom('en')
export const i18n = createI18n(locale, {
async get (code) {
return JSON.parse(await readFile(`/translations/${code}.json`))
}
})
export function getMessage (messages, lang, key) {
locale.set(locale)
return messages.get()[key]
}
export async function preloadLocales (locales) {
for (const i of locales) {
locale.set(i)
if (i18n.loading.get()) {
await new Promise(resolve => {
let unbindLoading = i18n.loading.listen(isLoading => {
if (!isLoading) {
unbindLoading()
resolve()
}
})
}
}
}
}
// app.js
import { preloadLocales } from './lib/i18n.js'
await preloadLocales(['de-DE'])
// errors.js
import { i18n, getMessage } from './lib/i18n.js'
let messages = i18n('errors', {
forbidden: 'Forbidden ヾ(・ω・)ノ. Insufficient Authorization.'
})
getMessage(messages, 'de-DE', 'forbidden')
from i18n.
We don't have sync API since it is not good for performance and Node.js is getting so many good things to write sync code easy.
Why do you need sync API in your case and can't use top-level await
?
from i18n.
@ai I could use await as well. the example above is a sketch and mostly I'm searching for away to quickly obtain the international string result from a locale or language string and a key.
from i18n.
https://github.com/mashpie/i18n-node (over 1mb btw) gives this '__mf' method for returning messages. Does nanostores/i18n expose anything like i18n-node's '__mf'?
import fs from 'fs';
import { I18n } from 'i18n';
const i18n = new I18n({
defaultLocale: 'en',
staticCatalog: {
en: JSON.parse( fs.readFileSync( 'en-US.json' ) )
}
});
// Hello Marcus
console.log( i18n.__mf('Hello {name}', { name: 'Marcus' }) );
from i18n.
Do you split your CLI tool by separated modules?
Our library promote component based approach which works great for web/desktop/mobile UI bit didn't fit all CLI cases.
from i18n.
My goal is to return ~40 internationalized error messages from a koa data-service. The service has a small number of routes and currently returns english messages. If it works out well, a different and bigger service will be updated in a similar way.
The only CLI tool I'm using so far is used to convert and pre-process language files
from i18n.
the application files look like this atm
msg.js
const msgErrorForbidden = () => (
'Forbidden ヾ(・ω・)ノ. Insufficient Authorization.' );
err.js
const errForbidden = err(
403, 2103, access_denied, msgErrorForbidden );
from i18n.
Helpers are big because our library was not created for this specific use case.
from i18n.
I released 0.5 version with a small helper to simplify this code:
// lib/i18n.js
import { atom } from 'nanostores'
- import { createI18n } from '@nanostores/i18n'
+ import { createI18n, translationsLoading } from '@nanostores/i18n'
import { readFile } from 'fs/promises'
export const locale = atom('en')
export const i18n = createI18n(locale, {
async get (code) {
return JSON.parse(await readFile(`/translations/${code}.json`))
}
})
export function getMessage (messages, lang, key) {
locale.set(locale)
return messages.get()[key]
}
export async function preloadLocales (locales) {
for (const i of locales) {
locale.set(i)
- if (i18n.loading.get()) {
- await new Promise(resolve => {
- let unbindLoading = i18n.loading.listen(isLoading => {
- if (!isLoading) {
- unbindLoading()
- resolve()
- }
- })
- }
- }
+ await translationsLoading(i18n)
}
}
from i18n.
thank you. the helper does simplify the setup
from i18n.
I've changed locale.set(locale)
to this locale.set(lang)
to avoid a runtime error. the default message is always returned to me in the example below. Adding logs to the createi18n get
shows the language files are loaded. Would you tell me what I'm doing wrong?
import { atom } from 'nanostores';
import { createI18n, translationsLoading } from '@nanostores/i18n';
import { readFile } from 'fs/promises';
export const locale = atom('en-US');
export const i18nano = createI18n(locale, {
async get (code) {
return JSON.parse( await readFile( `i18n.${code}.json` ) );
}
});
export function getMessage (messages, lang, key) {
locale.set(lang);
return messages.get()[key];
}
const preloadLocales = async locales => {
for (const i of locales) {
locale.set(i);
await translationsLoading(i18nano);
}
};
(async () => {
await preloadLocales(['en-US', 'ja-JP']);
let messages = i18nano('errors', {
login: 'fallback english login',
forbidden: 'Forbidden ヾ(・ω・)ノ. Insufficient Authorization.'
});
console.log( 'i18nano', getMessage(messages, 'en-US', 'login') );
console.log( 'i18nano', getMessage(messages, 'ja-JP', 'login') );
})();
from i18n.
cc @ai in case the closed state of the ticket prevents my question from reaching you
from i18n.
the locale files I'm using look like this
{
"login": "ログイン"
}
I've tried nesting the messages inside "error" like this, but the result is the same and the fallback english version message is always returned,
{
"error": {
"login": "ログイン"
}
}
from i18n.
The correct file is
{
"error": {
"login": "ログイン"
}
}
You also need to change base locale (default is en
):
export const i18nano = createI18n(locale, {
+ baseLocale: 'en-US'
async get (code) {
What is console.log
output?
from i18n.
import { atom } from 'nanostores';
import { createI18n, translationsLoading } from '@nanostores/i18n';
import { readFile } from 'fs/promises';
export const locale = atom('en');
export const i18nano = createI18n(locale, {
baseLocale: 'en-US',
async get (code) {
// return JSON.parse( await readFile( `i18n.${code}.json` ) );
return code === 'ja-JP'
? { errors: { login: "ログイン" } }
: { errors: { login: 'Log In' } };
}
});
export function getMessage (messages, lang, key) {
locale.set(lang);
return messages.get()[key];
}
const preloadLocales = async locales => {
for (const i of locales) {
locale.set(i);
await translationsLoading(i18nano);
}
};
(async () => {
await preloadLocales(['en-US', 'ja-JP']);
let messages = i18nano('errors', {
login: 'fallback english login',
forbidden: 'Forbidden ヾ(・ω・)ノ. Insufficient Authorization.'
});
console.log( 'i18nano', getMessage(messages, 'en-US', 'login') );
// i18nano fallback english login
console.log( 'i18nano', getMessage(messages, 'ja-JP', 'login') );
// i18nano fallback english login
})();
the above prints the below output,
$ node ./example.javascript.nano.js
i18nano fallback english login
i18nano fallback english login
from i18n.
You need:
- Call
let messages = i18nano()
beforeawait preloadLocales()
- Add
messages.listen(() => {})
to initialize messages store.
export const locale = atom('en')
export const i18nano = createI18n(locale, {
baseLocale: 'en-US',
async get(code) {
// return JSON.parse( await readFile( `i18n.${code}.json` ) );
if (code === 'ja-JP') return { errors: { login: 'ログイン' } }
else return { errors: { login: 'Log In' } }
}
})
export function getMessage(messages, lang, key) {
locale.set(lang)
return messages.get()[key]
}
const preloadLocales = async locales => {
for (let i of locales) {
locale.set(i)
await translationsLoading(i18nano)
}
}
let messages = i18nano('errors', {
login: 'fallback english login',
forbidden: 'Forbidden ヾ(・ω・)ノ. Insufficient Authorization.'
})
messages.listen(() => {})
;(async () => {
await preloadLocales(['en-US', 'ja-JP'])
console.log('i18nano', getMessage(messages, 'en-US', 'login'))
console.log('i18nano', getMessage(messages, 'ja-JP', 'login'))
})()
from i18n.
👍 thank you that works
from i18n.
@ai apologies for messaging you directly, otherwise I'm not sure if the 'closed' status of the ticket will surface my message to you. I'm trying to smoke-test parameters https://github.com/nanostores/i18n#parameters. How should I do this using the script above with { errors: { login: 'ログイン {username}' } }
?
from i18n.
Yes, JSON should be like
{ errors: { login: 'ログイン {username}' } }
from i18n.
import { atom } from 'nanostores';
import { createI18n, translationsLoading, params } from '@nanostores/i18n';
import { readFile } from 'fs/promises';
export const locale = atom('en');
export const i18nano = createI18n(locale, {
baseLocale: 'en-US',
async get(code) {
// return JSON.parse( await readFile( `i18n.${code}.json` ) );
return code === 'ja-JP'
? { errors: { login: 'ログイン {name}' } }
: { errors: { login: 'Log In' } };
}
});
export function getMessage(messages, lang, key, param) {
locale.set(lang);
const res = messages.get()[key];
if ( typeof res === 'function' )
return res(param);
return res;
}
const preloadLocales = async locales => {
for (let i of locales) {
locale.set(i);
await translationsLoading(i18nano);
}
};
let messages = i18nano('errors', {
login: params( 'fallback english login {name}' ),
forbidden: 'Forbidden ヾ(・ω・)ノ. Insufficient Authorization.'
});
messages.listen(() => {});
(async () => {
await preloadLocales(['en-US', 'ja-JP']);
console.log('i18nano', getMessage(messages, 'en-US', 'login', { name: 'jim' }));
console.log('i18nano', getMessage(messages, 'ja-JP', 'login', { name: 'jim' }));
})();
from i18n.
And what is output? (I am not with computer)
from i18n.
the output is
i18nano fallback english login jim
i18nano ログイン jim
from i18n.
thank you for your help!
from i18n.
actually, I'm not sure why 'en-US' returns the fallback and I'm unable to get it to return en-US 'Log In'
from i18n.
I see I suppose that's because it is the 'default' language... everything is good
from i18n.
I see I suppose that's because it is the 'default' language.
Yes. It is by design.
from i18n.
Related Issues (14)
- Translation preprocessor
- number, time and count functions type mismatch HOT 6
- Add HMR support HOT 1
- SSR Example HOT 4
- does nanostores/i18n process process lists in international way? HOT 1
- runtime error when NODE_ENV === 'production', HOT 6
- Prevent `baseTranslation` from flashing HOT 9
- Error while using useStore HOT 4
- Usage in sandboxes HOT 2
- Nesting of translations HOT 3
- Add partial translation loading HOT 2
- Generate types for `params()` automatically by TS string parsing
- Clears data from local storage after page refresh HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from i18n.