翻訳ファイルをランタイムで読み込み
This commit is contained in:
parent
ec4d5857d8
commit
84b488a912
6 changed files with 46 additions and 33 deletions
15
gulpfile.ts
15
gulpfile.ts
|
@ -2,6 +2,7 @@
|
||||||
* Gulp tasks
|
* Gulp tasks
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import * as fs from 'fs';
|
||||||
import * as gulp from 'gulp';
|
import * as gulp from 'gulp';
|
||||||
import * as ts from 'gulp-typescript';
|
import * as ts from 'gulp-typescript';
|
||||||
import * as rimraf from 'rimraf';
|
import * as rimraf from 'rimraf';
|
||||||
|
@ -31,6 +32,18 @@ gulp.task('build:copy:fonts', () =>
|
||||||
gulp.src('./node_modules/three/examples/fonts/**/*').pipe(gulp.dest('./built/client/assets/fonts/'))
|
gulp.src('./node_modules/three/examples/fonts/**/*').pipe(gulp.dest('./built/client/assets/fonts/'))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gulp.task('build:copy:locales', cb => {
|
||||||
|
fs.mkdirSync('./built/client/assets/locales', { recursive: true });
|
||||||
|
|
||||||
|
const v = { '_version_': meta.version };
|
||||||
|
|
||||||
|
for (const [lang, locale] of Object.entries(locales)) {
|
||||||
|
fs.writeFileSync(`./built/client/assets/locales/${lang}.${meta.version}.json`, JSON.stringify({ ...locale, ...v }), 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
|
||||||
gulp.task('build:client:script', () => {
|
gulp.task('build:client:script', () => {
|
||||||
return gulp.src(['./src/server/web/boot.js'])
|
return gulp.src(['./src/server/web/boot.js'])
|
||||||
.pipe(replace('VERSION', JSON.stringify(meta.version)))
|
.pipe(replace('VERSION', JSON.stringify(meta.version)))
|
||||||
|
@ -47,7 +60,7 @@ gulp.task('build:client:style', () => {
|
||||||
.pipe(gulp.dest('./built/server/web/'));
|
.pipe(gulp.dest('./built/server/web/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('build:copy', gulp.parallel('build:copy:views', 'build:client:script', 'build:client:style', 'build:copy:fonts', () =>
|
gulp.task('build:copy', gulp.parallel('build:copy:locales', 'build:copy:views', 'build:client:script', 'build:client:style', 'build:copy:fonts', () =>
|
||||||
gulp.src([
|
gulp.src([
|
||||||
'./src/emojilist.json',
|
'./src/emojilist.json',
|
||||||
'./src/server/web/views/**/*',
|
'./src/server/web/views/**/*',
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
{
|
{
|
||||||
"globals": {
|
"globals": {
|
||||||
"_DEV_": false,
|
"_DEV_": false,
|
||||||
"_LANG_": false,
|
|
||||||
"_LANGS_": false,
|
"_LANGS_": false,
|
||||||
"_LOCALE_": false,
|
|
||||||
"_VERSION_": false,
|
"_VERSION_": false,
|
||||||
"_ENV_": false,
|
"_ENV_": false,
|
||||||
"_PERF_PREFIX_": false,
|
"_PERF_PREFIX_": false,
|
||||||
|
|
2
src/client/@types/global.d.ts
vendored
2
src/client/@types/global.d.ts
vendored
|
@ -1,6 +1,4 @@
|
||||||
declare const _LANG_: string;
|
|
||||||
declare const _LANGS_: string[][];
|
declare const _LANGS_: string[][];
|
||||||
declare const _LOCALE_: Record<string, any>;
|
|
||||||
declare const _VERSION_: string;
|
declare const _VERSION_: string;
|
||||||
declare const _ENV_: string;
|
declare const _ENV_: string;
|
||||||
declare const _DEV_: boolean;
|
declare const _DEV_: boolean;
|
||||||
|
|
|
@ -6,9 +6,9 @@ export const hostname = address.hostname;
|
||||||
export const url = address.origin;
|
export const url = address.origin;
|
||||||
export const apiUrl = url + '/api';
|
export const apiUrl = url + '/api';
|
||||||
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
|
export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming';
|
||||||
export const lang = _LANG_;
|
export const lang = localStorage.getItem('lang');
|
||||||
export const langs = _LANGS_;
|
export const langs = _LANGS_;
|
||||||
export const locale = _LOCALE_; // TODO: code splittingするため、翻訳ファイルを分割したうえでwebpackのimport alias使って読み込むようにしたい
|
export const locale = JSON.parse(localStorage.getItem('locale'));
|
||||||
export const version = _VERSION_;
|
export const version = _VERSION_;
|
||||||
export const instanceName = siteName === 'Misskey' ? host : siteName;
|
export const instanceName = siteName === 'Misskey' ? host : siteName;
|
||||||
export const ui = localStorage.getItem('ui');
|
export const ui = localStorage.getItem('ui');
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* BOOT LOADER
|
* BOOT LOADER
|
||||||
* サーバーからレスポンスされるHTMLに埋め込まれるスクリプトで、以下の役割を持ちます。
|
* サーバーからレスポンスされるHTMLに埋め込まれるスクリプトで、以下の役割を持ちます。
|
||||||
* - バージョンやユーザーの言語に基づいて適切なメインスクリプトを読み込む。
|
* - 翻訳ファイルをフェッチする。
|
||||||
|
* - バージョンに基づいて適切なメインスクリプトを読み込む。
|
||||||
* - キャッシュされたコンパイル済みテーマを適用する。
|
* - キャッシュされたコンパイル済みテーマを適用する。
|
||||||
* - クライアントの設定値に基づいて対応するHTMLクラス等を設定する。
|
* - クライアントの設定値に基づいて対応するHTMLクラス等を設定する。
|
||||||
* テーマをこの段階で設定するのは、メインスクリプトが読み込まれる間もテーマを適用したいためです。
|
* テーマをこの段階で設定するのは、メインスクリプトが読み込まれる間もテーマを適用したいためです。
|
||||||
|
@ -10,27 +11,34 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔
|
// ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので
|
||||||
{
|
(async () => {
|
||||||
//#region Script
|
const v = localStorage.getItem('v') || VERSION;
|
||||||
|
|
||||||
//#region Detect language
|
//#region Detect language & fetch translations
|
||||||
const supportedLangs = LANGS;
|
if (localStorage.hasOwnProperty('locale')) {
|
||||||
let lang = localStorage.getItem('lang');
|
// TODO: 非同期でlocaleの更新処理をする
|
||||||
if (lang == null || !supportedLangs.includes(lang)) {
|
} else {
|
||||||
if (supportedLangs.includes(navigator.language)) {
|
const supportedLangs = LANGS;
|
||||||
lang = navigator.language;
|
let lang = localStorage.getItem('lang');
|
||||||
} else {
|
if (lang == null || !supportedLangs.includes(lang)) {
|
||||||
lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
|
if (supportedLangs.includes(navigator.language)) {
|
||||||
|
lang = navigator.language;
|
||||||
|
} else {
|
||||||
|
lang = supportedLangs.find(x => x.split('-')[0] === navigator.language);
|
||||||
|
|
||||||
// Fallback
|
// Fallback
|
||||||
if (lang == null) lang = 'en-US';
|
if (lang == null) lang = 'en-US';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const res = await fetch(`/assets/locales/${lang}.${v}.json`);
|
||||||
|
const json = await res.json();
|
||||||
|
localStorage.setItem('locale', JSON.stringify(json));
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
const ver = localStorage.getItem('v') || VERSION;
|
//#region Script
|
||||||
|
|
||||||
const salt = localStorage.getItem('salt')
|
const salt = localStorage.getItem('salt')
|
||||||
? `?salt=${localStorage.getItem('salt')}`
|
? `?salt=${localStorage.getItem('salt')}`
|
||||||
: '';
|
: '';
|
||||||
|
@ -38,7 +46,7 @@
|
||||||
const head = document.getElementsByTagName('head')[0];
|
const head = document.getElementsByTagName('head')[0];
|
||||||
|
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
script.setAttribute('src', `/assets/app.${ver}.${lang}.js${salt}`);
|
script.setAttribute('src', `/assets/app.${v}.js${salt}`);
|
||||||
script.setAttribute('async', 'true');
|
script.setAttribute('async', 'true');
|
||||||
script.setAttribute('defer', 'true');
|
script.setAttribute('defer', 'true');
|
||||||
head.appendChild(script);
|
head.appendChild(script);
|
||||||
|
@ -56,7 +64,7 @@
|
||||||
|
|
||||||
const meta = await res.json();
|
const meta = await res.json();
|
||||||
|
|
||||||
if (meta.version != ver) {
|
if (meta.version != v) {
|
||||||
localStorage.setItem('v', meta.version);
|
localStorage.setItem('v', meta.version);
|
||||||
alert(
|
alert(
|
||||||
'Misskeyの新しいバージョンがあります。ページを再度読み込みします。' +
|
'Misskeyの新しいバージョンがあります。ページを再度読み込みします。' +
|
||||||
|
@ -113,4 +121,4 @@
|
||||||
|
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
}
|
})();
|
||||||
|
|
|
@ -33,9 +33,7 @@ const postcss = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Object.keys(isProduction ? locales : {
|
module.exports = {
|
||||||
'ja-JP': locales['ja-JP']
|
|
||||||
}).map(lang => ({
|
|
||||||
entry: {
|
entry: {
|
||||||
app: './src/client/init.ts',
|
app: './src/client/init.ts',
|
||||||
sw: './src/client/sw/sw.ts'
|
sw: './src/client/sw/sw.ts'
|
||||||
|
@ -133,9 +131,7 @@ module.exports = Object.keys(isProduction ? locales : {
|
||||||
new webpack.ProgressPlugin({}),
|
new webpack.ProgressPlugin({}),
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
_VERSION_: JSON.stringify(meta.version),
|
_VERSION_: JSON.stringify(meta.version),
|
||||||
_LANG_: JSON.stringify(lang),
|
|
||||||
_LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]: [string, any]) => [k, v._lang_])),
|
_LANGS_: JSON.stringify(Object.entries(locales).map(([k, v]: [string, any]) => [k, v._lang_])),
|
||||||
_LOCALE_: JSON.stringify(locales[lang]),
|
|
||||||
_ENV_: JSON.stringify(process.env.NODE_ENV),
|
_ENV_: JSON.stringify(process.env.NODE_ENV),
|
||||||
_DEV_: process.env.NODE_ENV !== 'production',
|
_DEV_: process.env.NODE_ENV !== 'production',
|
||||||
_PERF_PREFIX_: JSON.stringify('Misskey:'),
|
_PERF_PREFIX_: JSON.stringify('Misskey:'),
|
||||||
|
@ -153,7 +149,7 @@ module.exports = Object.keys(isProduction ? locales : {
|
||||||
],
|
],
|
||||||
output: {
|
output: {
|
||||||
path: __dirname + '/built/client/assets',
|
path: __dirname + '/built/client/assets',
|
||||||
filename: `[name].${meta.version}.${lang}.js`,
|
filename: `[name].${meta.version}.js`,
|
||||||
publicPath: `/assets/`
|
publicPath: `/assets/`
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
|
@ -173,4 +169,4 @@ module.exports = Object.keys(isProduction ? locales : {
|
||||||
},
|
},
|
||||||
devtool: false, //'source-map',
|
devtool: false, //'source-map',
|
||||||
mode: isProduction ? 'production' : 'development'
|
mode: isProduction ? 'production' : 'development'
|
||||||
}));
|
};
|
||||||
|
|
Loading…
Reference in a new issue