Compare commits
	
		
			1 Commits
		
	
	
		
			chat
			...
			feat/bundl
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | f066247988 | 
| @@ -235,6 +235,7 @@ | |||||||
| 		"jest-mock": "29.7.0", | 		"jest-mock": "29.7.0", | ||||||
| 		"nodemon": "3.1.9", | 		"nodemon": "3.1.9", | ||||||
| 		"pid-port": "1.0.2", | 		"pid-port": "1.0.2", | ||||||
| 		"simple-oauth2": "5.1.0" | 		"simple-oauth2": "5.1.0", | ||||||
|  | 		"vite": "6.2.1" | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,10 +5,13 @@ | |||||||
|  |  | ||||||
| import * as fs from 'node:fs'; | import * as fs from 'node:fs'; | ||||||
| import { fileURLToPath } from 'node:url'; | import { fileURLToPath } from 'node:url'; | ||||||
| import { dirname, resolve } from 'node:path'; | import { dirname, join, resolve } from 'node:path'; | ||||||
| import * as yaml from 'js-yaml'; | import * as yaml from 'js-yaml'; | ||||||
| import * as Sentry from '@sentry/node'; | import * as Sentry from '@sentry/node'; | ||||||
|  | import locale from '../../../locales/index.js'; | ||||||
| import type { RedisOptions } from 'ioredis'; | import type { RedisOptions } from 'ioredis'; | ||||||
|  | import type { Manifest, ManifestChunk } from 'vite'; | ||||||
|  | import type { ILocale } from '../../../locales/index.js'; | ||||||
|  |  | ||||||
| type RedisOptionsSource = Partial<RedisOptions> & { | type RedisOptionsSource = Partial<RedisOptions> & { | ||||||
| 	host: string; | 	host: string; | ||||||
| @@ -185,9 +188,12 @@ export type Config = { | |||||||
| 	authUrl: string; | 	authUrl: string; | ||||||
| 	driveUrl: string; | 	driveUrl: string; | ||||||
| 	userAgent: string; | 	userAgent: string; | ||||||
| 	frontendEntry: string; | 	localeEntries: Record<string, string>; | ||||||
|  | 	errorLocaleMessages: Record<string, ILocale>; | ||||||
|  | 	configEntry: ManifestChunk; | ||||||
|  | 	frontendEntry: ManifestChunk; | ||||||
| 	frontendManifestExists: boolean; | 	frontendManifestExists: boolean; | ||||||
| 	frontendEmbedEntry: string; | 	frontendEmbedEntry: ManifestChunk; | ||||||
| 	frontendEmbedManifestExists: boolean; | 	frontendEmbedManifestExists: boolean; | ||||||
| 	mediaProxy: string; | 	mediaProxy: string; | ||||||
| 	externalMediaProxyEnabled: boolean; | 	externalMediaProxyEnabled: boolean; | ||||||
| @@ -229,12 +235,23 @@ export function loadConfig(): Config { | |||||||
|  |  | ||||||
| 	const frontendManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_vite_/manifest.json'); | 	const frontendManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_vite_/manifest.json'); | ||||||
| 	const frontendEmbedManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_embed_vite_/manifest.json'); | 	const frontendEmbedManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_embed_vite_/manifest.json'); | ||||||
| 	const frontendManifest = frontendManifestExists ? | 	const frontendManifest: Manifest = frontendManifestExists | ||||||
| 		JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_vite_/manifest.json`, 'utf-8')) | 		? JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_vite_/manifest.json`, 'utf-8')) | ||||||
| 		: { 'src/_boot_.ts': { file: 'src/_boot_.ts' } }; | 		: Object.entries(locale).reduce<Record<string, ManifestChunk>>((a, [k]) => { | ||||||
| 	const frontendEmbedManifest = frontendEmbedManifestExists ? | 			a[`locale:${k}`] = { file: `locale:${k}` }; | ||||||
| 		JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8')) | 			return a; | ||||||
| 		: { 'src/boot.ts': { file: 'src/boot.ts' } }; | 		}, { | ||||||
|  | 			'src/_boot_.ts': { file: 'src/_boot_.ts' }, | ||||||
|  | 			'../frontend-shared/js/config.ts': { file: join('@fs', _dirname.slice(1), '../../frontend-shared/js/config.ts') }, | ||||||
|  | 		}); | ||||||
|  | 	const frontendEmbedManifest: Manifest = frontendEmbedManifestExists | ||||||
|  | 		? JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8')) | ||||||
|  | 		: Object.entries(locale).reduce<Record<string, ManifestChunk>>((a, [k]) => { | ||||||
|  | 			a[`locale:${k}`] = { file: `locale:${k}` }; | ||||||
|  | 			return a; | ||||||
|  | 		}, { | ||||||
|  | 			'src/boot.ts': { file: 'src/boot.ts' }, | ||||||
|  | 		}); | ||||||
|  |  | ||||||
| 	const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source; | 	const config = yaml.load(fs.readFileSync(path, 'utf-8')) as Source; | ||||||
|  |  | ||||||
| @@ -310,6 +327,20 @@ export function loadConfig(): Config { | |||||||
| 			config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator | 			config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator | ||||||
| 			: null, | 			: null, | ||||||
| 		userAgent: `Misskey/${version} (${config.url})`, | 		userAgent: `Misskey/${version} (${config.url})`, | ||||||
|  | 		localeEntries: Object.entries<ManifestChunk>(frontendManifest).reduce<Record<string, string>>((a, [k, v]) => { | ||||||
|  | 			if (k.startsWith('locale:')) { | ||||||
|  | 				a[k.slice('locale:'.length)] = v.file; | ||||||
|  | 			} | ||||||
|  | 			return a; | ||||||
|  | 		}, {}), | ||||||
|  | 		errorLocaleMessages: Object.entries(locale).reduce<Record<string, ILocale>>((a, [k, v]) => { | ||||||
|  | 			a[k] = { | ||||||
|  | 				_bootErrors: v._bootErrors, | ||||||
|  | 				reload: v.reload, | ||||||
|  | 			}; | ||||||
|  | 			return a; | ||||||
|  | 		}, {}), | ||||||
|  | 		configEntry: frontendManifest['../frontend-shared/js/config.ts'], | ||||||
| 		frontendEntry: frontendManifest['src/_boot_.ts'], | 		frontendEntry: frontendManifest['src/_boot_.ts'], | ||||||
| 		frontendManifestExists: frontendManifestExists, | 		frontendManifestExists: frontendManifestExists, | ||||||
| 		frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'], | 		frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'], | ||||||
|   | |||||||
| @@ -32,10 +32,9 @@ | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	//#region Detect language & fetch translations | 	//#region Detect language & fetch translations | ||||||
| 	if (!localStorage.hasOwnProperty('locale')) { |  | ||||||
| 	const supportedLangs = LANGS; | 	const supportedLangs = LANGS; | ||||||
| 	let lang = localStorage.getItem('lang'); | 	let lang = localStorage.getItem('lang'); | ||||||
| 		if (lang == null || !supportedLangs.includes(lang)) { | 	if (!supportedLangs.includes(lang)) { | ||||||
| 		if (supportedLangs.includes(navigator.language)) { | 		if (supportedLangs.includes(navigator.language)) { | ||||||
| 			lang = navigator.language; | 			lang = navigator.language; | ||||||
| 		} else { | 		} else { | ||||||
| @@ -46,42 +45,11 @@ | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		const metaRes = await window.fetch('/api/meta', { | 	await import(`/vite/${LOCALES[lang]}`) | ||||||
| 			method: 'POST', | 		.catch(async e => { | ||||||
| 			body: JSON.stringify({}), | 			console.error(e); | ||||||
| 			credentials: 'omit', | 			renderError('LOCALE_FETCH', e); | ||||||
| 			cache: 'no-cache', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json', |  | ||||||
| 			}, |  | ||||||
| 		}); | 		}); | ||||||
| 		if (metaRes.status !== 200) { |  | ||||||
| 			renderError('META_FETCH'); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		const meta = await metaRes.json(); |  | ||||||
| 		const v = meta.version; |  | ||||||
| 		if (v == null) { |  | ||||||
| 			renderError('META_FETCH_V'); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// for https://github.com/misskey-dev/misskey/issues/10202 |  | ||||||
| 		if (lang == null || lang.toString == null || lang.toString() === 'null') { |  | ||||||
| 			console.error('invalid lang value detected!!!', typeof lang, lang); |  | ||||||
| 			lang = 'en-US'; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`); |  | ||||||
| 		if (localRes.status === 200) { |  | ||||||
| 			localStorage.setItem('lang', lang); |  | ||||||
| 			localStorage.setItem('locale', await localRes.text()); |  | ||||||
| 			localStorage.setItem('localeVersion', v); |  | ||||||
| 		} else { |  | ||||||
| 			renderError('LOCALE_FETCH'); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	//#endregion | 	//#endregion | ||||||
|  |  | ||||||
| 	//#region Script | 	//#region Script | ||||||
| @@ -115,10 +83,21 @@ | |||||||
| 			await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve)); | 			await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		const locale = JSON.parse(localStorage.getItem('locale') || '{}'); | 		const supportedLangs = LANGS; | ||||||
|  | 		let lang = localStorage.getItem('lang'); | ||||||
|  | 		if (!supportedLangs.includes(lang)) { | ||||||
|  | 			if (supportedLangs.includes(navigator.language)) { | ||||||
|  | 				lang = navigator.language; | ||||||
|  | 			} else { | ||||||
|  | 				lang = supportedLangs.find(x => x.split('-')[0] === navigator.language); | ||||||
|  |  | ||||||
| 		const title = locale?._bootErrors?.title || 'Failed to initialize Misskey'; | 				// Fallback | ||||||
| 		const reload = locale?.reload || 'Reload'; | 				if (lang == null) lang = 'en-US'; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		const { locale } = await import(`/vite/${CONFIG_ENTRY}`).catch(() => ({ locale: {} })); | ||||||
|  | 		const title = locale._bootErrors.title; | ||||||
|  | 		const reload = locale.reload; | ||||||
|  |  | ||||||
| 		document.body.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M12 9v4" /><path d="M12 16v.01" /></svg> | 		document.body.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M12 9v4" /><path d="M12 16v.01" /></svg> | ||||||
| 		<div class="message">${title}</div> | 		<div class="message">${title}</div> | ||||||
|   | |||||||
| @@ -23,10 +23,9 @@ | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	//#region Detect language & fetch translations | 	//#region Detect language & fetch translations | ||||||
| 	if (!localStorage.hasOwnProperty('locale')) { |  | ||||||
| 	const supportedLangs = LANGS; | 	const supportedLangs = LANGS; | ||||||
| 	let lang = localStorage.getItem('lang'); | 	let lang = localStorage.getItem('lang'); | ||||||
| 		if (lang == null || !supportedLangs.includes(lang)) { | 	if (!supportedLangs.includes(lang)) { | ||||||
| 		if (supportedLangs.includes(navigator.language)) { | 		if (supportedLangs.includes(navigator.language)) { | ||||||
| 			lang = navigator.language; | 			lang = navigator.language; | ||||||
| 		} else { | 		} else { | ||||||
| @@ -37,42 +36,11 @@ | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 		const metaRes = await window.fetch('/api/meta', { | 	await import(`/vite/${LOCALES[lang]}`) | ||||||
| 			method: 'POST', | 		.catch(async e => { | ||||||
| 			body: JSON.stringify({}), | 			console.error(e); | ||||||
| 			credentials: 'omit', | 			renderError('LOCALE_FETCH', e); | ||||||
| 			cache: 'no-cache', |  | ||||||
| 			headers: { |  | ||||||
| 				'Content-Type': 'application/json', |  | ||||||
| 			}, |  | ||||||
| 		}); | 		}); | ||||||
| 		if (metaRes.status !== 200) { |  | ||||||
| 			renderError('META_FETCH'); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 		const meta = await metaRes.json(); |  | ||||||
| 		const v = meta.version; |  | ||||||
| 		if (v == null) { |  | ||||||
| 			renderError('META_FETCH_V'); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// for https://github.com/misskey-dev/misskey/issues/10202 |  | ||||||
| 		if (lang == null || lang.toString == null || lang.toString() === 'null') { |  | ||||||
| 			console.error('invalid lang value detected!!!', typeof lang, lang); |  | ||||||
| 			lang = 'en-US'; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		const localRes = await window.fetch(`/assets/locales/${lang}.${v}.json`); |  | ||||||
| 		if (localRes.status === 200) { |  | ||||||
| 			localStorage.setItem('lang', lang); |  | ||||||
| 			localStorage.setItem('locale', await localRes.text()); |  | ||||||
| 			localStorage.setItem('localeVersion', v); |  | ||||||
| 		} else { |  | ||||||
| 			renderError('LOCALE_FETCH'); |  | ||||||
| 			return; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	//#endregion | 	//#endregion | ||||||
|  |  | ||||||
| 	//#region Script | 	//#region Script | ||||||
| @@ -151,21 +119,25 @@ | |||||||
| 			await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve)); | 			await new Promise(resolve => window.addEventListener('DOMContentLoaded', resolve)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		const locale = JSON.parse(localStorage.getItem('locale') || '{}'); | 		const supportedLangs = LANGS; | ||||||
|  | 		let lang = localStorage.getItem('lang'); | ||||||
|  | 		if (!supportedLangs.includes(lang)) { | ||||||
|  | 			if (supportedLangs.includes(navigator.language)) { | ||||||
|  | 				lang = navigator.language; | ||||||
|  | 			} else { | ||||||
|  | 				lang = supportedLangs.find(x => x.split('-')[0] === navigator.language); | ||||||
|  |  | ||||||
| 		const messages = Object.assign({ | 				// Fallback | ||||||
| 			title: 'Failed to initialize Misskey', | 				if (lang == null) lang = 'en-US'; | ||||||
| 			solution: 'The following actions may solve the problem.', | 			} | ||||||
| 			solution1: 'Update your os and browser', | 		} | ||||||
| 			solution2: 'Disable an adblocker', | 		const { locale } = await import(`/vite/${CONFIG_ENTRY}`).catch(() => ({ | ||||||
| 			solution3: 'Clear the browser cache', | 			locale: { | ||||||
| 			solution4: '(Tor Browser) Set dom.webaudio.enabled to true', | 				_bootErrors: {}, | ||||||
| 			otherOption: 'Other options', | 			}, | ||||||
| 			otherOption1: 'Clear preferences and cache', | 		})); | ||||||
| 			otherOption2: 'Start the simple client', | 		const messages = locale._bootErrors; | ||||||
| 			otherOption3: 'Start the repair tool', | 		const reload = locale.reload; | ||||||
| 		}, locale?._bootErrors || {}); |  | ||||||
| 		const reload = locale?.reload || 'Reload'; |  | ||||||
|  |  | ||||||
| 		let errorsElement = document.getElementById('errors'); | 		let errorsElement = document.getElementById('errors'); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,23 +6,22 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| (() => { | (() => { | ||||||
| 	document.addEventListener('DOMContentLoaded', () => { | 	document.addEventListener('DOMContentLoaded', async () => { | ||||||
| 		const locale = JSON.parse(localStorage.getItem('locale') || '{}'); | 		const supportedLangs = LANGS; | ||||||
|  | 		let lang = localStorage.getItem('lang'); | ||||||
|  | 		if (!supportedLangs.includes(lang)) { | ||||||
|  | 			if (supportedLangs.includes(navigator.language)) { | ||||||
|  | 				lang = navigator.language; | ||||||
|  | 			} else { | ||||||
|  | 				lang = supportedLangs.find(x => x.split('-')[0] === navigator.language); | ||||||
|  |  | ||||||
| 		const messages = Object.assign({ | 				// Fallback | ||||||
| 			title: 'Failed to initialize Misskey', | 				if (lang == null) lang = 'en-US'; | ||||||
| 			serverError: 'If reloading after a period of time does not resolve the problem, contact the server administrator with the following ERROR ID.', | 			} | ||||||
| 			solution: 'The following actions may solve the problem.', | 		} | ||||||
| 			solution1: 'Update your os and browser', | 		const locale = ERROR_MESSAGES[lang]; | ||||||
| 			solution2: 'Disable an adblocker', | 		const messages = locale._bootErrors; | ||||||
| 			solution3: 'Clear the browser cache', | 		const reload = locale.reload; | ||||||
| 			solution4: '(Tor Browser) Set dom.webaudio.enabled to true', |  | ||||||
| 			otherOption: 'Other options', |  | ||||||
| 			otherOption1: 'Clear preferences and cache', |  | ||||||
| 			otherOption2: 'Start the simple client', |  | ||||||
| 			otherOption3: 'Start the repair tool', |  | ||||||
| 		}, locale?._bootErrors || {}); |  | ||||||
| 		const reload = locale?.reload || 'Reload'; |  | ||||||
|  |  | ||||||
| 		const reloadEls = document.querySelectorAll('[data-i18n-reload]'); | 		const reloadEls = document.querySelectorAll('[data-i18n-reload]'); | ||||||
| 		for (const el of reloadEls) { | 		for (const el of reloadEls) { | ||||||
|   | |||||||
| @@ -41,6 +41,8 @@ html(class='embed') | |||||||
| 		script. | 		script. | ||||||
| 			var VERSION = "#{version}"; | 			var VERSION = "#{version}"; | ||||||
| 			var CLIENT_ENTRY = "#{entry.file}"; | 			var CLIENT_ENTRY = "#{entry.file}"; | ||||||
|  | 			var CONFIG_ENTRY = "#{config.configEntry.file}"; | ||||||
|  | 			var LOCALES = JSON.parse(`!{JSON.stringify(config.localeEntries)}`); | ||||||
|  |  | ||||||
| 		script(type='application/json' id='misskey_meta' data-generated-at=now) | 		script(type='application/json' id='misskey_meta' data-generated-at=now) | ||||||
| 			!= metaJson | 			!= metaJson | ||||||
|   | |||||||
| @@ -70,6 +70,8 @@ html | |||||||
| 		script. | 		script. | ||||||
| 			var VERSION = "#{version}"; | 			var VERSION = "#{version}"; | ||||||
| 			var CLIENT_ENTRY = "#{entry.file}"; | 			var CLIENT_ENTRY = "#{entry.file}"; | ||||||
|  | 			var CONFIG_ENTRY = "#{config.configEntry.file}"; | ||||||
|  | 			var LOCALES = JSON.parse(`!{JSON.stringify(config.localeEntries)}`); | ||||||
|  |  | ||||||
| 		script(type='application/json' id='misskey_meta' data-generated-at=now) | 		script(type='application/json' id='misskey_meta' data-generated-at=now) | ||||||
| 			!= metaJson | 			!= metaJson | ||||||
|   | |||||||
| @@ -27,6 +27,9 @@ html | |||||||
| 		style | 		style | ||||||
| 			include ../error.css | 			include ../error.css | ||||||
|  |  | ||||||
|  | 		script. | ||||||
|  | 			var ERROR_MESSAGES = JSON.parse(`!{JSON.stringify(config.errorLocaleMessages)}`); | ||||||
|  |  | ||||||
| 		script | 		script | ||||||
| 			include ../error.js | 			include ../error.js | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,18 +13,17 @@ import { createApp, defineAsyncComponent } from 'vue'; | |||||||
| import defaultLightTheme from '@@/themes/l-light.json5'; | import defaultLightTheme from '@@/themes/l-light.json5'; | ||||||
| import defaultDarkTheme from '@@/themes/d-dark.json5'; | import defaultDarkTheme from '@@/themes/d-dark.json5'; | ||||||
| import { MediaProxy } from '@@/js/media-proxy.js'; | import { MediaProxy } from '@@/js/media-proxy.js'; | ||||||
|  | import { url, version, locale, lang, updateLocale } from '@@/js/config.js'; | ||||||
|  | import { parseEmbedParams } from '@@/js/embed-page.js'; | ||||||
|  | import type { Theme } from '@/theme.js'; | ||||||
| import { applyTheme, assertIsTheme } from '@/theme.js'; | import { applyTheme, assertIsTheme } from '@/theme.js'; | ||||||
| import { fetchCustomEmojis } from '@/custom-emojis.js'; | import { fetchCustomEmojis } from '@/custom-emojis.js'; | ||||||
| import { DI } from '@/di.js'; | import { DI } from '@/di.js'; | ||||||
| import { serverMetadata } from '@/server-metadata.js'; | import { serverMetadata } from '@/server-metadata.js'; | ||||||
| import { url, version, locale, lang, updateLocale } from '@@/js/config.js'; |  | ||||||
| import { parseEmbedParams } from '@@/js/embed-page.js'; |  | ||||||
| import { postMessageToParentWindow, setIframeId } from '@/post-message.js'; | import { postMessageToParentWindow, setIframeId } from '@/post-message.js'; | ||||||
| import { serverContext } from '@/server-context.js'; | import { serverContext } from '@/server-context.js'; | ||||||
| import { i18n, updateI18n } from '@/i18n.js'; | import { i18n, updateI18n } from '@/i18n.js'; | ||||||
|  |  | ||||||
| import type { Theme } from '@/theme.js'; |  | ||||||
|  |  | ||||||
| console.log('Misskey Embed'); | console.log('Misskey Embed'); | ||||||
|  |  | ||||||
| //#region Embedパラメータの取得・パース | //#region Embedパラメータの取得・パース | ||||||
| @@ -71,22 +70,6 @@ if (embedParams.colorMode === 'dark') { | |||||||
| } | } | ||||||
| //#endregion | //#endregion | ||||||
|  |  | ||||||
| //#region Detect language & fetch translations |  | ||||||
| const localeVersion = localStorage.getItem('localeVersion'); |  | ||||||
| const localeOutdated = (localeVersion == null || localeVersion !== version || locale == null); |  | ||||||
| if (localeOutdated) { |  | ||||||
| 	const res = await window.fetch(`/assets/locales/${lang}.${version}.json`); |  | ||||||
| 	if (res.status === 200) { |  | ||||||
| 		const newLocale = await res.text(); |  | ||||||
| 		const parsedNewLocale = JSON.parse(newLocale); |  | ||||||
| 		localStorage.setItem('locale', newLocale); |  | ||||||
| 		localStorage.setItem('localeVersion', version); |  | ||||||
| 		updateLocale(parsedNewLocale); |  | ||||||
| 		updateI18n(parsedNewLocale); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| //#endregion |  | ||||||
|  |  | ||||||
| // サイズの制限 | // サイズの制限 | ||||||
| document.documentElement.style.maxWidth = '500px'; | document.documentElement.style.maxWidth = '500px'; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -17,8 +17,7 @@ export const apiUrl = location.origin + '/api'; | |||||||
| export const wsOrigin = location.origin; | export const wsOrigin = location.origin; | ||||||
| export const lang = localStorage.getItem('lang') ?? 'en-US'; | export const lang = localStorage.getItem('lang') ?? 'en-US'; | ||||||
| export const langs = _LANGS_; | export const langs = _LANGS_; | ||||||
| const preParseLocale = localStorage.getItem('locale'); | export let locale: Locale; | ||||||
| export let locale: Locale = preParseLocale ? JSON.parse(preParseLocale) : null; |  | ||||||
| export const version = _VERSION_; | export const version = _VERSION_; | ||||||
| export const instanceName = (siteName === 'Misskey' || siteName == null) ? host : siteName; | export const instanceName = (siteName === 'Misskey' || siteName == null) ? host : siteName; | ||||||
| export const ui = localStorage.getItem('ui'); | export const ui = localStorage.getItem('ui'); | ||||||
|   | |||||||
| @@ -55,7 +55,6 @@ function initLocalStorage() { | |||||||
| 		...userDetailed(), | 		...userDetailed(), | ||||||
| 		policies: {}, | 		policies: {}, | ||||||
| 	})); | 	})); | ||||||
| 	localStorage.setItem('locale', JSON.stringify(locale)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| initialize({ | initialize({ | ||||||
| @@ -70,13 +69,17 @@ queueMicrotask(() => { | |||||||
| 		import('../src/theme.js'), | 		import('../src/theme.js'), | ||||||
| 		import('../src/preferences.js'), | 		import('../src/preferences.js'), | ||||||
| 		import('../src/os.js'), | 		import('../src/os.js'), | ||||||
| 	]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os]) => { | 		import('../src/i18n.js'), | ||||||
|  | 		import('../../frontend-shared/js/config.js'), | ||||||
|  | 	]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os, { updateI18n }, { updateLocale }]) => { | ||||||
| 		setup((app) => { | 		setup((app) => { | ||||||
| 			moduleInitialized = true; | 			moduleInitialized = true; | ||||||
| 			if (app[appInitialized]) { | 			if (app[appInitialized]) { | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| 			app[appInitialized] = true; | 			app[appInitialized] = true; | ||||||
|  | 			updateLocale(locale); | ||||||
|  | 			updateI18n(locale); | ||||||
| 			loadTheme(applyTheme); | 			loadTheme(applyTheme); | ||||||
| 			components(app); | 			components(app); | ||||||
| 			directives(app); | 			directives(app); | ||||||
|   | |||||||
| @@ -78,22 +78,6 @@ export async function common(createVue: () => App<Element>) { | |||||||
| 	} | 	} | ||||||
| 	//#endregion | 	//#endregion | ||||||
|  |  | ||||||
| 	//#region Detect language & fetch translations |  | ||||||
| 	const localeVersion = miLocalStorage.getItem('localeVersion'); |  | ||||||
| 	const localeOutdated = (localeVersion == null || localeVersion !== version || locale == null); |  | ||||||
| 	if (localeOutdated) { |  | ||||||
| 		const res = await window.fetch(`/assets/locales/${lang}.${version}.json`); |  | ||||||
| 		if (res.status === 200) { |  | ||||||
| 			const newLocale = await res.text(); |  | ||||||
| 			const parsedNewLocale = JSON.parse(newLocale); |  | ||||||
| 			miLocalStorage.setItem('locale', newLocale); |  | ||||||
| 			miLocalStorage.setItem('localeVersion', version); |  | ||||||
| 			updateLocale(parsedNewLocale); |  | ||||||
| 			updateI18n(parsedNewLocale); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	//#endregion |  | ||||||
|  |  | ||||||
| 	// タッチデバイスでCSSの:hoverを機能させる | 	// タッチデバイスでCSSの:hoverを機能させる | ||||||
| 	window.document.addEventListener('touchend', () => {}, { passive: true }); | 	window.document.addEventListener('touchend', () => {}, { passive: true }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,8 +23,8 @@ export type Keys = ( | |||||||
| 	'fontSize' | | 	'fontSize' | | ||||||
| 	'ui' | | 	'ui' | | ||||||
| 	'ui_temp' | | 	'ui_temp' | | ||||||
| 	'locale' | | 	'locale' | // DEPRECATED | ||||||
| 	'localeVersion' | | 	'localeVersion' | // DEPRECATED | ||||||
| 	'theme' | | 	'theme' | | ||||||
| 	'themeId' | | 	'themeId' | | ||||||
| 	'customCss' | | 	'customCss' | | ||||||
|   | |||||||
| @@ -606,8 +606,6 @@ const defaultFollowWithReplies = prefer.model('defaultFollowWithReplies'); | |||||||
|  |  | ||||||
| watch(lang, () => { | watch(lang, () => { | ||||||
| 	miLocalStorage.setItem('lang', lang.value as string); | 	miLocalStorage.setItem('lang', lang.value as string); | ||||||
| 	miLocalStorage.removeItem('locale'); |  | ||||||
| 	miLocalStorage.removeItem('localeVersion'); |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
| watch([ | watch([ | ||||||
|   | |||||||
| @@ -13,8 +13,10 @@ export async function clearCache() { | |||||||
| 	os.waiting(); | 	os.waiting(); | ||||||
| 	miLocalStorage.removeItem('instance'); | 	miLocalStorage.removeItem('instance'); | ||||||
| 	miLocalStorage.removeItem('instanceCachedAt'); | 	miLocalStorage.removeItem('instanceCachedAt'); | ||||||
|  | 	//#region deprecated | ||||||
| 	miLocalStorage.removeItem('locale'); | 	miLocalStorage.removeItem('locale'); | ||||||
| 	miLocalStorage.removeItem('localeVersion'); | 	miLocalStorage.removeItem('localeVersion'); | ||||||
|  | 	//#endregion | ||||||
| 	miLocalStorage.removeItem('theme'); | 	miLocalStorage.removeItem('theme'); | ||||||
| 	miLocalStorage.removeItem('emojis'); | 	miLocalStorage.removeItem('emojis'); | ||||||
| 	miLocalStorage.removeItem('lastEmojisFetchedAt'); | 	miLocalStorage.removeItem('lastEmojisFetchedAt'); | ||||||
|   | |||||||
| @@ -99,6 +99,30 @@ export function getConfig(): UserConfig { | |||||||
| 			pluginVue(), | 			pluginVue(), | ||||||
| 			pluginUnwindCssModuleClassName(), | 			pluginUnwindCssModuleClassName(), | ||||||
| 			pluginJson5(), | 			pluginJson5(), | ||||||
|  | 			{ | ||||||
|  | 				name: 'misskey:locale', | ||||||
|  | 				load: { | ||||||
|  | 					async handler(id) { | ||||||
|  | 						if (id.startsWith('locale:')) { | ||||||
|  | 							const locale = id.slice('locale:'.length); | ||||||
|  | 							return ` | ||||||
|  | 								import { updateLocale } from '@@/js/config.js'; | ||||||
|  | 								updateLocale(JSON.parse(${JSON.stringify(JSON.stringify(locales[locale]))})); | ||||||
|  | 							`; | ||||||
|  | 						} | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				resolveId: { | ||||||
|  | 					async handler(source, importer, options) { | ||||||
|  | 						if (source.startsWith('locale:')) { | ||||||
|  | 							return source; | ||||||
|  | 						} | ||||||
|  | 						if (importer === path.resolve(__dirname, 'index.html') && source.startsWith('/locale:')) { | ||||||
|  | 							return source.slice(1); | ||||||
|  | 						} | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
| 			...process.env.NODE_ENV === 'production' | 			...process.env.NODE_ENV === 'production' | ||||||
| 				? [ | 				? [ | ||||||
| 					pluginReplace({ | 					pluginReplace({ | ||||||
| @@ -162,9 +186,7 @@ export function getConfig(): UserConfig { | |||||||
| 			], | 			], | ||||||
| 			manifest: 'manifest.json', | 			manifest: 'manifest.json', | ||||||
| 			rollupOptions: { | 			rollupOptions: { | ||||||
| 				input: { | 				input: ['@/_boot_.ts', '@@/js/config.ts', ...Object.keys(locales).map(locale => `locale:${locale}`)], | ||||||
| 					app: './src/_boot_.ts', |  | ||||||
| 				}, |  | ||||||
| 				external: externalPackages.map(p => p.match), | 				external: externalPackages.map(p => p.match), | ||||||
| 				output: { | 				output: { | ||||||
| 					manualChunks: { | 					manualChunks: { | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										15
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @@ -594,6 +594,9 @@ importers: | |||||||
|       simple-oauth2: |       simple-oauth2: | ||||||
|         specifier: 5.1.0 |         specifier: 5.1.0 | ||||||
|         version: 5.1.0 |         version: 5.1.0 | ||||||
|  |       vite: | ||||||
|  |         specifier: 6.2.1 | ||||||
|  |         version: 6.2.1(@types/node@22.13.4)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) | ||||||
|     optionalDependencies: |     optionalDependencies: | ||||||
|       '@swc/core-android-arm64': |       '@swc/core-android-arm64': | ||||||
|         specifier: 1.3.11 |         specifier: 1.3.11 | ||||||
| @@ -21846,6 +21849,18 @@ snapshots: | |||||||
|  |  | ||||||
|   vite-plugin-turbosnap@1.0.3: {} |   vite-plugin-turbosnap@1.0.3: {} | ||||||
|  |  | ||||||
|  |   vite@6.2.1(@types/node@22.13.4)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3): | ||||||
|  |     dependencies: | ||||||
|  |       esbuild: 0.25.0 | ||||||
|  |       postcss: 8.5.3 | ||||||
|  |       rollup: 4.34.9 | ||||||
|  |     optionalDependencies: | ||||||
|  |       '@types/node': 22.13.4 | ||||||
|  |       fsevents: 2.3.3 | ||||||
|  |       sass: 1.85.1 | ||||||
|  |       terser: 5.39.0 | ||||||
|  |       tsx: 4.19.3 | ||||||
|  |  | ||||||
|   vite@6.2.1(@types/node@22.13.9)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3): |   vite@6.2.1(@types/node@22.13.9)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3): | ||||||
|     dependencies: |     dependencies: | ||||||
|       esbuild: 0.25.0 |       esbuild: 0.25.0 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user