diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 000000000..2817cde42 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,8 @@ +project_id: 518556 +preserve_hierarchy: true +commit_message: '[ci skip]' + +files: + - source: /locales/en-US/* + dest: /%original_file_name% + translation: /locales/%locale%/%original_file_name% diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index 2deaf495c..ca764b079 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -1,7 +1,11 @@ -import { resolve } from 'path' +import { resolve, basename } from 'path' import svgLoader from 'vite-svg-loader' import eslintPlugin from 'vite-plugin-eslint' +import { icuMessages } from '@vintl/unplugin/vite' +import virtual from '@rollup/plugin-virtual' +import { globSync } from 'glob' +/** @type {import('vitepress').SiteConfig} */ export default { title: 'Omorphia', description: 'A components library used for Modrinth.', @@ -75,11 +79,46 @@ export default { }, }), eslintPlugin(), + icuMessages({ + filter(id) { + // console.log('filter', id) + return id.endsWith('.json?messages') + }, + pluginsWrapping: true, + }), + virtual({ + '@modrinth/omorphia-dev/locales/index.js': (() => { + const localeDirs = globSync('../../locales/*', { cwd: __dirname, absolute: true }) + let fileContents = '' + fileContents += 'export const localeDefinitions = Object.create(null);\n' + console.log(localeDirs) + for (const localeDir of localeDirs) { + const tag = basename(localeDir) + fileContents += `localeDefinitions[${JSON.stringify(tag)}] = {\n` + fileContents += '\tasync importFunction() {\n' + fileContents += `\t\tconst messages = Object.create(null);\n` + for (const filePath of globSync('*', { cwd: localeDir, absolute: true })) { + const fileName = basename(filePath) + if (fileName === 'index.json') { + fileContents += `\t\tObject.assign(messages, await import(${JSON.stringify( + `${filePath}?messages` + )}).then((mod) => mod['default']));\n` + } + } + fileContents += '\t\treturn { messages }\n' + fileContents += '\t},\n' + fileContents += '}\n' + } + console.log(fileContents) + return fileContents + })(), + }), ], resolve: { alias: { '@': resolve(__dirname, '../../lib'), omorphia: resolve(__dirname, '../../lib'), + '@formatjs/icu-messageformat-parser': '@formatjs/icu-messageformat-parser/lib/no-parser', }, dedupe: ['vue'], }, diff --git a/docs/.vitepress/env.d.ts b/docs/.vitepress/env.d.ts new file mode 100644 index 000000000..aee340352 --- /dev/null +++ b/docs/.vitepress/env.d.ts @@ -0,0 +1,13 @@ +/// + +declare module '#locales/index.js' { + const localeDefinitions: Record< + string, + { + importFunction(): Promise<{ + messages: any + }> + } + > + export { localeDefinitions } +} diff --git a/docs/.vitepress/theme/LanguageSwitcher.vue b/docs/.vitepress/theme/LanguageSwitcher.vue new file mode 100644 index 000000000..19710210a --- /dev/null +++ b/docs/.vitepress/theme/LanguageSwitcher.vue @@ -0,0 +1,78 @@ + + + diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js index c814ca5f9..452db7aad 100644 --- a/docs/.vitepress/theme/index.js +++ b/docs/.vitepress/theme/index.js @@ -1,13 +1,48 @@ import DefaultTheme from 'vitepress/theme' -import Omorphia from 'omorphia' +import { plugin as omorphia } from 'omorphia' import DemoContainer from './DemoContainer.vue' +import { createPlugin } from '@vintl/vintl/plugin' +import { h } from 'vue' +import LanguageSwitcher from './LanguageSwitcher.vue' +import { localeDefinitions } from '@modrinth/omorphia-dev/locales/index.js' import './compat.scss' +/** @type {import('vitepress').Theme} */ export default { ...DefaultTheme, enhanceApp(ctx) { - ctx.app.use(Omorphia) + ctx.app.use(omorphia) ctx.app.component('DemoContainer', DemoContainer) + ctx.app.use( + createPlugin({ + controllerOpts: { + locales: Object.keys(localeDefinitions).map((tag) => ({ tag })), + listen: { + async localeload(event) { + const locale = event.locale.tag + if (!Object.hasOwn(localeDefinitions, locale)) { + throw new Error(`Unknown locale: ${locale}`) + } + + try { + const { messages } = await localeDefinitions[locale].importFunction() + event.addMessages(messages) + } catch (err) { + console.error(`Failed to load locale: ${locale}`, err) + } + }, + }, + }, + globalMixin: false, + }) + ) + }, + Layout() { + return h(DefaultTheme.Layout, null, { + 'sidebar-nav-before'() { + return h(LanguageSwitcher) + }, + }) }, } diff --git a/lib/components/base/CopyCode.vue b/lib/components/base/CopyCode.vue index db5f409c6..d34753fa2 100644 --- a/lib/components/base/CopyCode.vue +++ b/lib/components/base/CopyCode.vue @@ -1,5 +1,5 @@