Skip to content
This repository has been archived by the owner on Aug 28, 2024. It is now read-only.

Commit

Permalink
Add support for translations using VIntl
Browse files Browse the repository at this point in the history
Adds support for translations using VIntl module as a peer dependency.

TODO: better description
  • Loading branch information
brawaru committed Oct 23, 2023
1 parent 11fef06 commit 3a93e3d
Show file tree
Hide file tree
Showing 12 changed files with 702 additions and 45 deletions.
8 changes: 8 additions & 0 deletions crowdin.yml
Original file line number Diff line number Diff line change
@@ -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%
41 changes: 40 additions & 1 deletion docs/.vitepress/config.js
Original file line number Diff line number Diff line change
@@ -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.',
Expand Down Expand Up @@ -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'],
},
Expand Down
13 changes: 13 additions & 0 deletions docs/.vitepress/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// <reference types="vite/client" />

declare module '#locales/index.js' {
const localeDefinitions: Record<
string,
{
importFunction(): Promise<{
messages: any
}>
}
>
export { localeDefinitions }
}
78 changes: 78 additions & 0 deletions docs/.vitepress/theme/LanguageSwitcher.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useVIntl } from '@vintl/vintl'
import { DropdownSelect } from 'omorphia'
const { $locales, $config, changeLocale } = useVIntl()
const getLocaleDisplayName = (() => {
const cache = new Map<string, Intl.DisplayNames>()
return function getLocaleDisplayName(locale: string) {
let displayNames = cache.get(locale)
if (displayNames == null) {
displayNames = new Intl.DisplayNames(locale, {
type: 'language',
languageDisplay: 'standard',
})
cache.set(locale, displayNames)
}
return displayNames.of(locale)
}
})()
const isChanging = ref(false)
const currentLocale = computed({
get() {
return $config.locale
},
async set(value) {
if (isChanging.value) return
try {
isChanging.value = true
await changeLocale(value)
} finally {
isChanging.value = false
}
},
})
</script>
<template>
<div class="LanguageSwitcher">
<h2 class="title">Playground language</h2>

<DropdownSelect
v-model="currentLocale"
:options="Array.from($locales).map(([{ tag }]) => tag)"
placeholder="Change language"
:display-name="(locale: string) => getLocaleDisplayName(locale)"
class="locale-dropdown"
name="locale"
/>

<!-- <select v-model="currentLocale" :disabled="isChanging">
<option v-for="[locale] in $locales" :key="locale.tag" :value="locale.tag">
{{ getLocaleDisplayName(locale.tag) }}
</option>
</select> -->
</div>
</template>
<style scoped>
.LanguageSwitcher {
padding-block: 18px;
border-bottom: 1px solid var(--vp-c-divider);
}
.LanguageSwitcher .title {
font-weight: 700;
font-size: 14px;
color: var(--vp-c-text-1);
}
.LanguageSwitcher .locale-dropdown {
width: 200px;
font-size: 14px;
}
</style>
39 changes: 37 additions & 2 deletions docs/.vitepress/theme/index.js
Original file line number Diff line number Diff line change
@@ -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)
},
})
},
}
8 changes: 7 additions & 1 deletion lib/components/base/CopyCode.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<button class="code" :class="{ copied }" title="Copy code to clipboard" @click="copyText">
<button class="code" :class="{ copied }" :title="formatMessage(copiedMessage)" @click="copyText">
<span>{{ text }}</span>
<CheckIcon v-if="copied" />
<ClipboardCopyIcon v-else />
Expand All @@ -8,6 +8,12 @@

<script setup>
import { CheckIcon, ClipboardCopyIcon } from '@'
import { useVIntl, defineMessage } from '@vintl/vintl'
const copiedMessage = defineMessage({
id: 'omorphia.component.copy.action.copy',
defaultMessage: 'Copy code to clipboard',
})
const { formatMessage } = useVIntl()
</script>

<script>
Expand Down
5 changes: 5 additions & 0 deletions locales/en-US/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"omorphia.component.copy.action.copy": {
"defaultMessage": "Copy code to clipboard"
}
}
5 changes: 5 additions & 0 deletions locales/uk/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"omorphia.component.copy.action.copy": {
"defaultMessage": "Скопіювати код до буфера обміну"
}
}
14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
"type": "module",
"version": "0.6.2",
"files": [
"dist"
"dist",
"locales"
],
"module": "./dist/omorphia.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/omorphia.js"
},
"./locales/*.json": {
"import": "./locales/*.json"
},
"./dist/style.css": "./dist/style.css"
},
"scripts": {
Expand All @@ -20,7 +24,8 @@
"fix": "eslint --fix --ext .js,.vue,.ts,.jsx,.tsx,.html,.vue . && prettier --write .",
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
"docs:preview": "vitepress preview docs",
"intl:extract": "formatjs extract \"lib/**/*.{vue,ts,tsx,js,jsx,mts,cts,mjs,cjs}\" --ignore \"lib/**/*.d.ts\" --out-file locales/en-US.json --preserve-whitespace"
},
"dependencies": {
"@codemirror/commands": "^6.3.0",
Expand All @@ -40,13 +45,18 @@
"xss": "^1.0.14"
},
"devDependencies": {
"@formatjs/cli": "^6.2.1",
"@rollup/plugin-virtual": "^3.0.2",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"@vintl/unplugin": "^1.5.1",
"@vintl/vintl": "^4.3.0",
"@vitejs/plugin-vue": "^4.2.3",
"eslint": "^8.41.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.14.1",
"glob": "^10.3.10",
"postcss": "^8.4.24",
"postcss-prefix-selector": "^1.16.0",
"prettier": "^2.8.8",
Expand Down
Loading

0 comments on commit 3a93e3d

Please sign in to comment.