Use same resource for languages with different IETF language tag in i18next - i18next

I have the following code:
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import locales from 'locales'
const resources = {
en: locales.en,
no: locales.no,
de: locales.de,
se: locales.se
}
function getDefaultLocale() {
const preferredLanguage = localStorage.getItem('preferredLanguage')
const lng = locales.languages
.map(({ code }) => code)
.find(code =>
code === preferredLanguage || // The user has set a preferred language
code === '__DEFAULT_LOCALE__' || // Default locale set at build time.
code === navigator.language
)
return lng
}
i18n
.use(initReactI18next)
.init({
resources,
lng: getDefaultLocale(),
appendNamespaceToCIMode: true
})
export default i18n
My problem is, that let's say when the English language is detected with navigator.language, it may be en, en-US, en-GB, or for Norwegian, it may be nb, nb-NO, ny-NO etc.
We would like to serve the same translations for all English language codes, and the same for all the Norwegian language codes.
My current solution is to defined resources like so:
const resources = {
en: locales.en,
'en-US': locales.en,
'en-GB': locales.en,
no: locales.no,
'nb-NO': locales.no,
'ny-NO': locales.no,
de: locales.de,
se: locales.se
}
But there must be a better solution to this! Could someone help?

Default behaviour for locales containing region is to fallback to the primary language code.
For instance, we have detected en-GB, but there is not translation file assigned to this locale. Assuming that en translations are in place, expected behaviour would be to proceed with them, not causing any trouble.
This practically means you can remove duplicate declaration from your initialization code:
const resources = {
en: locales.en,
no: locales.no,
de: locales.de,
se: locales.se
}
If you prefer, it could be done in a more concise manner:
const resources = { ...locales }

Related

How to Load Custom Language in Monaco using VueJS/Webpack

I've created a custom language using this tool here. I don't know what to do to load it to my VueJS app. I tried the following and get no errors, but it also doesn't show seem to work, because in the Monarch tool thing I get blue text on known functions etc, but in my editor I don't. Other languages work as expected.
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
const path = require('path');
const main = path.resolve(__dirname, './src/test/test.ts');
module.exports = {
configureWebpack: {
plugins: [
new MonacoWebpackPlugin({
languages: ['javascript', 'typescript', 'python', 'java', 'python', 'json', 'vb'],
customLanguages: [
{
label: 'test',
entry: main
}
]
})
]
}
...
I made my .ts file essentially export a conf property with all the variables or whatever that are used in the tokenizer. I also exported a language property. I'm not totally sure that is the right format.
My .ts file essentially looks like:
export const conf = {...}
export const language = {...}
I'm not totally sure what to do here. Docs are sparse for custom languages and nothing seems to be working other than I think I at least have the first part of defining the language working.
That Webpack plugin isn't actually needed.
Based on the custom language example, you can register the language at runtime via monaco.languages.setMonarchTokensProvider(). The second function argument is an instance of IMonarchLanguage, which matches the language spec in the example you linked.
<script setup lang="ts">
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'
import { ref, onMounted } from 'vue'
/**
* `customLangMonarch` contains the language spec example from
* https://microsoft.github.io/monaco-editor/monarch.html
*/
// #ts-ignore
import customLangMonarch from '#/custom-lang-monarch'
monaco.languages.register({ id: 'custom' })
monaco.languages.setMonarchTokensProvider('custom', customLangMonarch)
const editor = ref()
onMounted(() => {
monaco.editor.create(editor.value, {
language: 'custom',
})
})
</script>
demo w/Vue CLI
demo w/Vite

How can i customize form error message from Yup/Vee-validate using Vue-i18n in Ionic VueJS

I would like to use vue-i18n to translate my form error messages.
I've code a "lang.ts" file which builds my i18n instance like this :
import { createI18n } from 'vue-i18n';
import french from './i18n/fr-FR.json';
import english from './i18n/en-US.json';
// push translations to list
const messages = {
'en-US': french,
'fr-FR': english
}
// Create VueI18n instance with options
export const i18n = createI18n({
locale:"en-US",
messages
});
and I initialize all of this in my "main.ts"
...
const app = createApp(App).use(router);
router.isReady().then(() => {
Device.getLanguageCode().then(function (lang) {
i18n.global.locale = lang.value; // changing locale using Capacitor locale getter
app.use(i18n)
.use(IonicVue)
app.mount('#app');
});
});
I'm using a yup custom schema to validate my form, and that's where i mention my custom error message, the problem is that my "global" locale value isn't being used in my schema and it always translates to default language (en-US here...)
here's my schema
export const LoginFormContentSchema = yup
.object({
login: yup.object({
email: yup.string().email(i18n.global.t('wrongMail')).required(i18n.global.t('emptyMail')), // translating my error messages to current global locale
password: yup.string().required(i18n.global.t('emptyPassword')),
url: yup
.string()
.required(i18n.global.t("urlEmpty")).lowercase()
.matches(/^(https:\/\/)?[a-z0-9._-]+(\.fr)/),
}),
})
.required();
Since i've changed my locale before mounting the app, i should have fr-FR as locale everywhere, but i'm getting "en-US" outputs when the error message pops out even thought my device is in French and my global.locale is fr-FR.

How do I translate Quasar component?

I have a Vue/Quasar application in which I use i18n but now I'm facing a problem: table footer doesn't get translated. In the table headers, for example, I do something like this to translate column names:
{
align: 'left',
field: (val) => val,
label: this.$t('locale.column'),
name: 'column',
required: true,
sortable: true,
},
where $t is 18n function, locale is my component and the column is actually's column's name. I don't have direct access to the footer of the table (where the pagination an the total number of the elements are) and it doesn't get translated. I also use Quasar language packs, quasar.js goes like this:
import en from 'quasar/lang/en-us.js'
/*
import other languages
*/
import {
state,
} from '#state/modules/i18n';
const locale = state.locale;
const langDictionary = {
// all the imported langs go here
};
Vue.use(Quasar, {
config: {},
components: { /* not needed if importStrategy is not 'manual' */ },
directives: { /* not needed if importStrategy is not 'manual' */ },
plugins: {
Cookies,
Dialog,
Loading,
Notify,
},
lang: langDictionary[locale]
});
export {langDictionary};
You are probably setting the language at startup correctly as lang: langDictionary[locale]. If you change the language state in your app later, you need to also inform Quasar if you want Quasar components and plugins to get correctly translated. See the docs, Change Quasar Language Pack at Runtime for how to achieve that, the docs about language pack also includes tips for dynamically loading the language pack.
You didn't specify how you change the language in your app, so I can't give an example built upon that.

Can I make VueI18n fallback on a key path if not found the complete key path?

Is it possible for VueI18n to fall back to shorter key if it didn't found it.
A example for this could be, I have following messages:
{
en: {
"hello": "This is the fallback message!",
"admin.hello": "This is some other message for another context"
}
}
The below code is a illustration of what the results should be:
{{ $t("does.not.exists.hello") }} // should fallback on hello, so the result will be "This is the fallback message!"
{{ $t("admin.hello") }} // Message exists so the result should be "This is some other message for another context"
{{ $t("hello") }} // Message exists so the result should be "This is the fallback message!"
Okay I was to fast, with this question. MissingHandler is useful for this.
and the code example became like this:
Vue.use(VueI18n)
// Create VueI18n instance with options
export default new VueI18n({
locale: 'en', // set locale
silentTranslationWarn: true,
missing: (locale: Locale, key: Path, vm?: Vue) => {
if(key.includes(".")) {
let newKey = /\.(.+)/.exec(key)[1];
console.log(newKey)
return vm.$t(newKey) as string
}
return key
},
//formatter: new CustomFormatter(),
fallbackLocale: 'en',
messages // set locale messages
})

Turn off translations for react-admin

Developing an admin that has no need for translations. Is there a way to turn them off completely. As it is now, for things like doing notifications, they display but I also get a console warning about missing key for translation.
In addition to Frederik's answer, here's the right way to disable the 'missing translations' warnings on react-admin:
import polyglotI18nProvider from 'ra-i18n-polyglot'; // install the package
import englishMessages from 'ra-language-english'; // install the package
const App = () => {
const i18nProvider = polyglotI18nProvider(() => englishMessages, 'en', { allowMissing: true });
return (
<Admin i18nProvider={i18nProvider}
...
/>
)
}
Solved it by adding a custom i18nProvider that allows missing keys:
const i18nProvider = polyglotI18nProvider(locale => i18nMessages[locale], 'en', { allowMissing: true });
<Admin
i18nProvider={i18nProvider}
...
/>
More details: https://marmelab.com/react-admin/Translation.html
and: https://www.npmjs.com/package/node-polyglot#options-overview