Open volarname opened 2 years ago
Would love to have support for this! Currently, I'm having to cram all my i18n strings into one JSON file to make it work, and that route is really not scalable.
i made for now my custom load for this. for now without dynamic import (all languages and all files are imported) vite is a requirement for this (glob import and load of yaml, but probably can be replaced by some library for webpack):
// @/locales/index.js
// note: now import is not dynamic, so all language files are loaded at once
const modules = import.meta.globEager('./(sk|en)/**/*.yaml', { assert: { type: 'yaml' } })
const setValueByPath = (obj: any, path: string, value: any, splitChar = '.') => {
const a = path.split(splitChar)
let o = obj
while (a.length - 1) {
const n = a.shift()
if (isUndefined(n)) return
if (!(n in o)) o[n] = {}
o = o[n]
}
o[a[0]] = value
}
const cleanupKey = (key: string) => {
key = key.substring(2)
return key.substring(0, key.indexOf('.'))
}
const final = {}
for (const key in modules) {
const path = cleanupKey(key)
setValueByPath(final, path, modules[key].default, '/')
}
export const messages = final
// @/utils/object.js
then just import messages to i18n config.
then file with this path @/locales/en/blog/article.json
with content (note first folder is lang code):
field:
title: Title
body: Bodytext
button:
save: Save
will be transformed to these keys under en language, for example:
const { t } = useI18n({ useScope: 'global' })
t('blog.article.field.title')
t('blog.article.field.body')
t('blog.article.button.save')
i think this can work with json also. i still prefer a solution from authors, for now i can have this as temp solution. just wondering this is still not implemented as a base feature
Yeah, import.meta.globEager
(import.meta.glob
) is useful.
I would consider implementing it, but it's a proprietary feature that is not standardized in ECMAScript (tc39) or elsewhere.
Since this plugin is for Vite, I would be willing to provide the functionality, but I'm a bit reluctant to rely on a non-standardized feature to implement it 😅
The yaml parser for import.meta.glob
behaves poorly.
Specifically, the following YAML fails to parse (checked with YAML Lint and eslint-plugin-yaml):
some-messages:
- first message
- second message
Therefore, I implemented parsing with js-yaml.
import yaml from 'js-yaml';
/** Return value */
const entries: any = {};
// Get locale yaml file.
Object.entries(
import.meta.glob('./(en|ja)/**/*.yml', {
eager: true,
as: 'raw',
})
).forEach(module => {
/** File Path */
const path = module[0];
/** Locale */
const locale = path.slice(2, 4);
/** Key name */
const key = path.slice(5, -4).replace(/\//, '.');
/** Yaml value */
const value = yaml.load(module[1]);
if (key === 'index') {
// Set index.yml to root.
entries[locale] = { ...entries[locale], ...value };
} else {
// Otherwise, assign to child object
const entry = {};
entry[key] = value;
entries[locale] = { ...entries[locale], ...entry };
}
});
export const messages = entries;
index.yml is assigned to root.
It's not very clean code, but I think it will work.
The reason was that Vite does not include a yaml parser. https://github.com/vitejs/vite/issues/10318
I use ts and vite import to manage all translation files. So, I can do a lots of things.
//configuration/locale.ts export const supportedLocales = { en: { name: "English" }, "zh-CN": { name: "中文简体" }, "zh-TW": { name: "中文繁體" }, };
export const defaultLocale = "en";
//locale/index.ts import { supportedLocales } from "@/configuration/locale"; import { merge } from "lodash";
const autoImportedLangs: Record<string, () => Promise
for (const path in autoImportedLangs) { const lang: string = path.substring( path.lastIndexOf("/") + 1, path.lastIndexOf(".") ); if (lang in usedLangs) { merge(usedLangs[lang], autoImportedLangs[path]); } }
export default usedLangs;
install the plugin:
import { createI18n } from "vue-i18n"; import { defaultLocale } from "@/configuration/locale"; import messages from "@/locales";
export default createI18n({ locale: defaultLocale, fallbackWarn: false, missingWarn: false, legacy: false, fallbackLocale: defaultLocale, messages, });
Clear and concise description of the problem
Suggested solution
locales/fr/group1/subject1.yaml locales/fr/group1/subject2.yaml locales/fr/group2/subject3.yaml
foo: foo bar: baz: baz
group1: subject1: foo: foo bar: baz: baz
en: group1: subject1: foo: foo bar: baz: baz
fr: group1: subject1: foo: foo bar: baz: baz