Merge branch 'master' into l10n_master
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -10,3 +10,4 @@ npm-debug.log | ||||
| run.bat | ||||
| api-docs.json | ||||
| package-lock.json | ||||
| yarn.lock | ||||
|   | ||||
| @@ -25,7 +25,7 @@ ultimately sophisticated new type of mini-blog based SNS. | ||||
| * Real time contents | ||||
| * ActivityPub compatible | ||||
|  | ||||
| and more! You can touch with your own eyes at https://misskey.xyz/. | ||||
| and more! You can touch with your own eyes at [misskey.xyz](https://misskey.xyz). | ||||
|  | ||||
| :package: Create your instance | ||||
| ---------------------------------------------------------------- | ||||
| @@ -36,7 +36,9 @@ please see [Setup and installation guide](./docs/setup.en.md). | ||||
| ---------------------------------------------------------------- | ||||
| **[PR](https://github.com/syuilo/misskey/pulls)s welcome!** | ||||
|  | ||||
| If you want to translate Misskey, please see [Translation guide](./docs/translate.en.md). | ||||
| If you want to... | ||||
| * i18n ... please see [Translation guide](./docs/translate.en.md). | ||||
| * l10n ... please visit https://crowdin.com/project/misskey | ||||
|  | ||||
| :heart: Backers & Sponsors | ||||
| ---------------------------------------------------------------- | ||||
|   | ||||
							
								
								
									
										3
									
								
								crowdin.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								crowdin.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| files: | ||||
|   - source: /locales/ja.yml | ||||
|     translation: /locales/%two_letters_code%.yml | ||||
| @@ -19,7 +19,7 @@ common: | ||||
|     wednesday: "W" | ||||
|     thursday: "T" | ||||
|     friday: "F" | ||||
|     saturday: "土" | ||||
|     saturday: "S" | ||||
|   reactions: | ||||
|     like: "Like" | ||||
|     love: "Love" | ||||
|   | ||||
| @@ -19,7 +19,7 @@ common: | ||||
|     wednesday: "M" | ||||
|     thursday: "J" | ||||
|     friday: "V" | ||||
|     saturday: "土" | ||||
|     saturday: "S" | ||||
|   reactions: | ||||
|     like: "Aime" | ||||
|     love: "Adore" | ||||
|   | ||||
| @@ -14,7 +14,7 @@ const langs = { | ||||
| 	'en': loadLang('en'), | ||||
| 	'fr': loadLang('fr'), | ||||
| 	'ja': native, | ||||
|  'pl': loadLang('pl') | ||||
| 	'pl': loadLang('pl') | ||||
| }; | ||||
|  | ||||
| Object.entries(langs).map(([, locale]) => { | ||||
|   | ||||
| @@ -20,7 +20,7 @@ common: | ||||
|     wednesday: "水" | ||||
|     thursday: "木" | ||||
|     friday: "金" | ||||
|     satruday: "土" | ||||
|     saturday: "土" | ||||
|  | ||||
|   reactions: | ||||
|     like: "いいね" | ||||
| @@ -366,6 +366,12 @@ desktop/views/components/settings.profile.vue: | ||||
|   birthday: "誕生日" | ||||
|   save: "保存" | ||||
|  | ||||
| desktop/views/components/timeline.vue: | ||||
|   home: "ホーム" | ||||
|   local: "ローカル" | ||||
|   global: "グローバル" | ||||
|   list: "リスト" | ||||
|  | ||||
| desktop/views/components/ui.header.account.vue: | ||||
|   profile: "プロフィール" | ||||
|   drive: "ドライブ" | ||||
|   | ||||
| @@ -19,7 +19,7 @@ common: | ||||
|     wednesday: "Ś" | ||||
|     thursday: "C" | ||||
|     friday: "P" | ||||
|     saturday: "土" | ||||
|     saturday: "S" | ||||
|   reactions: | ||||
|     like: "Lubię" | ||||
|     love: "Kocham" | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import locale from '../../locales'; | ||||
| export default class Replacer { | ||||
| 	private lang: string; | ||||
|  | ||||
| 	public pattern = /%i18n:([a-z0-9_\-@\.\!]+?)%/g; | ||||
| 	public pattern = /%i18n:([a-z0-9_\-\.\/\|\!]+?)%/g; | ||||
|  | ||||
| 	constructor(lang: string) { | ||||
| 		this.lang = lang; | ||||
| @@ -53,23 +53,20 @@ export default class Replacer { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public replacement(ctx, match, key) { | ||||
| 		const client = '/src/client/app/'; | ||||
| 		let name = null; | ||||
| 	public replacement(match, key) { | ||||
| 		let path = null; | ||||
|  | ||||
| 		const shouldEscape = key[0] == '!'; | ||||
| 		if (shouldEscape) { | ||||
| 			key = key.substr(1); | ||||
| 		} | ||||
|  | ||||
| 		if (key[0] == '@') { | ||||
| 			name = ctx.src.substr(ctx.src.indexOf(client) + client.length); | ||||
| 			key = key.substr(1); | ||||
| 		if (key.indexOf('|') != -1) { | ||||
| 			path = key.split('|')[0]; | ||||
| 			key = key.split('|')[1]; | ||||
| 		} | ||||
|  | ||||
| 		if (ctx && ctx.lang) this.lang = ctx.lang; | ||||
|  | ||||
| 		const txt = this.get(name, key); | ||||
| 		const txt = this.get(path, key); | ||||
|  | ||||
| 		return shouldEscape | ||||
| 			? txt.replace(/'/g, '\\x27').replace(/"/g, '\\x22') | ||||
|   | ||||
| @@ -64,7 +64,7 @@ export default Vue.extend({ | ||||
| 				'%i18n:!common.weekday-short.wednesday%', | ||||
| 				'%i18n:!common.weekday-short.thursday%', | ||||
| 				'%i18n:!common.weekday-short.friday%', | ||||
| 				'%i18n:!common.weekday-short.satruday%' | ||||
| 				'%i18n:!common.weekday-short.saturday%' | ||||
| 			] | ||||
| 		}; | ||||
| 	}, | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| <template> | ||||
| <div class="mk-timeline"> | ||||
| 	<header> | ||||
| 		<span :data-active="src == 'home'" @click="src = 'home'">%fa:home% ホーム</span> | ||||
| 		<span :data-active="src == 'local'" @click="src = 'local'">%fa:R comments% ローカル</span> | ||||
| 		<span :data-active="src == 'global'" @click="src = 'global'">%fa:globe% グローバル</span> | ||||
| 		<span :data-active="src == 'home'" @click="src = 'home'">%fa:home% %i18n:@home%</span> | ||||
| 		<span :data-active="src == 'local'" @click="src = 'local'">%fa:R comments% %i18n:@local%</span> | ||||
| 		<span :data-active="src == 'global'" @click="src = 'global'">%fa:globe% %i18n:@global%</span> | ||||
| 		<span :data-active="src == 'list'" @click="src = 'list'" v-if="list">%fa:list% {{ list.title }}</span> | ||||
| 		<button @click="chooseList" title="リスト">%fa:list%</button> | ||||
| 		<button @click="chooseList" title="%i18n:@list%">%fa:list%</button> | ||||
| 	</header> | ||||
| 	<x-core v-if="src == 'home'" ref="tl" key="home" src="home"/> | ||||
| 	<x-core v-if="src == 'local'" ref="tl" key="local" src="local"/> | ||||
|   | ||||
| @@ -87,6 +87,7 @@ export interface ILocalUser extends IUserBase { | ||||
|  | ||||
| export interface IRemoteUser extends IUserBase { | ||||
| 	inbox: string; | ||||
| 	endpoints: string[]; | ||||
| 	uri: string; | ||||
| 	url?: string; | ||||
| 	publicKey: { | ||||
| @@ -114,7 +115,7 @@ export function validatePassword(password: string): boolean { | ||||
| } | ||||
|  | ||||
| export function isValidName(name?: string): boolean { | ||||
| 	return name === null || (typeof name == 'string' && name.length < 30 && name.trim() != ''); | ||||
| 	return name === null || (typeof name == 'string' && name.length < 50 && name.trim() != ''); | ||||
| } | ||||
|  | ||||
| export function isValidDescription(description: string): boolean { | ||||
|   | ||||
| @@ -14,7 +14,7 @@ export default async (job: kue.Job, done): Promise<void> => { | ||||
| 			done(); | ||||
| 		} else { | ||||
| 			console.warn(`deliver failed: ${res.statusMessage}`); | ||||
| 			done(res); | ||||
| 			done(res.statusMessage); | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -49,6 +49,7 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs | ||||
| 		object == null || | ||||
| 		object.type !== 'Person' || | ||||
| 		typeof object.preferredUsername !== 'string' || | ||||
| 		typeof object.inbox !== 'string' || | ||||
| 		!validateUsername(object.preferredUsername) || | ||||
| 		!isValidName(object.name == '' ? null : object.name) | ||||
| 	) { | ||||
| @@ -100,6 +101,7 @@ export async function createPerson(value: any, resolver?: Resolver): Promise<IUs | ||||
| 				publicKeyPem: person.publicKey.publicKeyPem | ||||
| 			}, | ||||
| 			inbox: person.inbox, | ||||
| 			endpoints: person.endpoints, | ||||
| 			uri: person.id, | ||||
| 			url: person.url | ||||
| 		}) as IRemoteUser; | ||||
| @@ -207,7 +209,8 @@ export async function updatePerson(value: string | IObject, resolver?: Resolver) | ||||
| 			followingCount, | ||||
| 			notesCount, | ||||
| 			name: person.name, | ||||
| 			url: person.url | ||||
| 			url: person.url, | ||||
| 			endpoints: person.endpoints | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
|   | ||||
| @@ -50,6 +50,7 @@ export interface IPerson extends IObject { | ||||
| 	followers: any; | ||||
| 	following: any; | ||||
| 	outbox: any; | ||||
| 	endpoints: string[]; | ||||
| } | ||||
|  | ||||
| export const isCollection = (object: IObject): object is ICollection => | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { lib as emojilib } from 'emojilib'; | ||||
| import { JSDOM } from 'jsdom'; | ||||
| import config from '../config'; | ||||
|  | ||||
| const handlers = { | ||||
| 	bold({ document }, { bold }) { | ||||
| @@ -43,7 +44,7 @@ const handlers = { | ||||
|  | ||||
| 	mention({ document }, { content }) { | ||||
| 		const a = document.createElement('a'); | ||||
| 		a.href = '/' + content; | ||||
| 		a.href = `${config.url}/${content}`; | ||||
| 		a.textContent = content; | ||||
| 		document.body.appendChild(a); | ||||
| 	}, | ||||
|   | ||||
| @@ -13,6 +13,7 @@ const WebpackOnBuildPlugin = require('on-build-webpack'); | ||||
| const ProgressBarPlugin = require('progress-bar-webpack-plugin'); | ||||
|  | ||||
| import I18nReplacer from './src/build/i18n'; | ||||
| import { pattern as i18nPattern, replacement as i18nReplacement } from './webpack/i18n'; | ||||
| import { pattern as faPattern, replacement as faReplacement } from './src/build/fa'; | ||||
| const constants = require('./src/const.json'); | ||||
| import config from './src/config'; | ||||
| @@ -37,183 +38,154 @@ global['collapseSpacesReplacement'] = html => { | ||||
| global['base64replacement'] = (_, key) => { | ||||
| 	return fs.readFileSync(__dirname + '/src/client/' + key, 'base64'); | ||||
| }; | ||||
|  | ||||
| global['i18nReplacement'] = i18nReplacement; | ||||
|  | ||||
| //#endregion | ||||
|  | ||||
| const langs = Object.keys(locales); | ||||
|  | ||||
| // 無圧縮スクリプトを用意するのは重いので一時的に無効化 | ||||
| //const entries = process.env.NODE_ENV == 'production' | ||||
| //	? langs.map(l => [l, false]).concat(langs.map(l => [l, true])) | ||||
| //	: langs.map(l => [l, false]); | ||||
| const entries = process.env.NODE_ENV == 'production' | ||||
| 	? langs.map(l => [l, true]) | ||||
| 	: langs.map(l => [l, false]); | ||||
| const isProduction = process.env.NODE_ENV == 'production'; | ||||
|  | ||||
| module.exports = entries.map(x => { | ||||
| 	const [lang, isProduction] = x; | ||||
| // Entries | ||||
| const entry = { | ||||
| 	desktop: './src/client/app/desktop/script.ts', | ||||
| 	mobile: './src/client/app/mobile/script.ts', | ||||
| 	//stats: './src/client/app/stats/script.ts', | ||||
| 	//status: './src/client/app/status/script.ts', | ||||
| 	dev: './src/client/app/dev/script.ts', | ||||
| 	auth: './src/client/app/auth/script.ts', | ||||
| 	sw: './src/client/app/sw.js' | ||||
| }; | ||||
|  | ||||
| 	// Chunk name | ||||
| 	const name = lang; | ||||
| const output = { | ||||
| 	path: __dirname + '/built/client/assets', | ||||
| 	filename: `[name].${version}.-.${isProduction ? 'min' : 'raw'}.js` | ||||
| }; | ||||
|  | ||||
| 	// Entries | ||||
| 	const entry = { | ||||
| 		desktop: './src/client/app/desktop/script.ts', | ||||
| 		mobile: './src/client/app/mobile/script.ts', | ||||
| 		//ch: './src/client/app/ch/script.ts', | ||||
| 		//stats: './src/client/app/stats/script.ts', | ||||
| 		//status: './src/client/app/status/script.ts', | ||||
| 		dev: './src/client/app/dev/script.ts', | ||||
| 		auth: './src/client/app/auth/script.ts', | ||||
| 		sw: './src/client/app/sw.js' | ||||
| 	}; | ||||
| //#region Define consts | ||||
| const consts = { | ||||
| 	_RECAPTCHA_SITEKEY_: config.recaptcha.site_key, | ||||
| 	_SW_PUBLICKEY_: config.sw ? config.sw.public_key : null, | ||||
| 	_THEME_COLOR_: constants.themeColor, | ||||
| 	_COPYRIGHT_: constants.copyright, | ||||
| 	_VERSION_: version, | ||||
| 	_CODENAME_: codename, | ||||
| 	_STATUS_URL_: config.status_url, | ||||
| 	_STATS_URL_: config.stats_url, | ||||
| 	_DOCS_URL_: config.docs_url, | ||||
| 	_API_URL_: config.api_url, | ||||
| 	_WS_URL_: config.ws_url, | ||||
| 	_DEV_URL_: config.dev_url, | ||||
| 	_LANG_: '%lang%', | ||||
| 	_HOST_: config.host, | ||||
| 	_HOSTNAME_: config.hostname, | ||||
| 	_URL_: config.url, | ||||
| 	_LICENSE_: licenseHtml, | ||||
| 	_GOOGLE_MAPS_API_KEY_: config.google_maps_api_key | ||||
| }; | ||||
|  | ||||
| 	const output = { | ||||
| 		path: __dirname + '/built/client/assets', | ||||
| 		filename: `[name].${version}.${lang}.${isProduction ? 'min' : 'raw'}.js` | ||||
| 	}; | ||||
| const _consts = {}; | ||||
|  | ||||
| 	const i18nReplacer = new I18nReplacer(lang as string); | ||||
| 	global['i18nReplacement'] = i18nReplacer.replacement; | ||||
| Object.keys(consts).forEach(key => { | ||||
| 	_consts[key] = JSON.stringify(consts[key]); | ||||
| }); | ||||
| //#endregion | ||||
|  | ||||
| 	//#region Define consts | ||||
| 	const consts = { | ||||
| 		_RECAPTCHA_SITEKEY_: config.recaptcha.site_key, | ||||
| 		_SW_PUBLICKEY_: config.sw ? config.sw.public_key : null, | ||||
| 		_THEME_COLOR_: constants.themeColor, | ||||
| 		_COPYRIGHT_: constants.copyright, | ||||
| 		_VERSION_: version, | ||||
| 		_CODENAME_: codename, | ||||
| 		_STATUS_URL_: config.status_url, | ||||
| 		_STATS_URL_: config.stats_url, | ||||
| 		_DOCS_URL_: config.docs_url, | ||||
| 		_API_URL_: config.api_url, | ||||
| 		_WS_URL_: config.ws_url, | ||||
| 		_DEV_URL_: config.dev_url, | ||||
| 		_LANG_: lang, | ||||
| 		_HOST_: config.host, | ||||
| 		_HOSTNAME_: config.hostname, | ||||
| 		_URL_: config.url, | ||||
| 		_LICENSE_: licenseHtml, | ||||
| 		_GOOGLE_MAPS_API_KEY_: config.google_maps_api_key | ||||
| 	}; | ||||
| const plugins = [ | ||||
| 	//new HardSourceWebpackPlugin(), | ||||
| 	new ProgressBarPlugin({ | ||||
| 		format: chalk`  {cyan.bold yes we can} {bold [}:bar{bold ]} {green.bold :percent} {gray (:current/:total)} :elapseds`, | ||||
| 		clear: false | ||||
| 	}), | ||||
| 	new webpack.DefinePlugin(_consts), | ||||
| 	new webpack.DefinePlugin({ | ||||
| 		'process.env.NODE_ENV': JSON.stringify(isProduction ? 'production' : 'development') | ||||
| 	}), | ||||
| 	new WebpackOnBuildPlugin(stats => { | ||||
| 		fs.writeFileSync('./built/client/meta.json', JSON.stringify({ | ||||
| 			version | ||||
| 		}), 'utf-8'); | ||||
|  | ||||
| 	const _consts = {}; | ||||
| 		//#region i18n | ||||
| 		langs.forEach(lang => { | ||||
| 			Object.keys(entry).forEach(file => { | ||||
| 				let src = fs.readFileSync(`${__dirname}/built/client/assets/${file}.${version}.-.${isProduction ? 'min' : 'raw'}.js`, 'utf8'); | ||||
|  | ||||
| 	Object.keys(consts).forEach(key => { | ||||
| 		_consts[key] = JSON.stringify(consts[key]); | ||||
| 	}); | ||||
| 	//#endregion | ||||
| 				const i18nReplacer = new I18nReplacer(lang); | ||||
|  | ||||
| 	const plugins = [ | ||||
| 		//new HardSourceWebpackPlugin(), | ||||
| 		new ProgressBarPlugin({ | ||||
| 			format: chalk`  {cyan.bold yes we can} {bold [}:bar{bold ]} {green.bold :percent} {gray (:current/:total)} :elapseds`, | ||||
| 			clear: false | ||||
| 		}), | ||||
| 		new webpack.DefinePlugin(_consts), | ||||
| 		new webpack.DefinePlugin({ | ||||
| 			'process.env.NODE_ENV': JSON.stringify(isProduction ? 'production' : 'development') | ||||
| 		}), | ||||
| 		new WebpackOnBuildPlugin(stats => { | ||||
| 			fs.writeFileSync('./built/client/meta.json', JSON.stringify({ | ||||
| 				version | ||||
| 			}), 'utf-8'); | ||||
| 		}), | ||||
| 		new VueLoaderPlugin() | ||||
| 	]; | ||||
| 				src = src.replace(i18nReplacer.pattern, i18nReplacer.replacement); | ||||
| 				src = src.replace('%lang%', lang); | ||||
|  | ||||
| 	if (isProduction) { | ||||
| 		plugins.push(new webpack.optimize.ModuleConcatenationPlugin()); | ||||
| 	} | ||||
| 				fs.writeFileSync(`${__dirname}/built/client/assets/${file}.${version}.${lang}.${isProduction ? 'min' : 'raw'}.js`, src, 'utf8'); | ||||
| 			}); | ||||
| 		}); | ||||
| 		//#endregion | ||||
| 	}), | ||||
| 	new VueLoaderPlugin() | ||||
| ]; | ||||
|  | ||||
| 	return { | ||||
| 		name, | ||||
| 		entry, | ||||
| 		module: { | ||||
| 			rules: [{ | ||||
| 				test: /\.vue$/, | ||||
| 				exclude: /node_modules/, | ||||
| 				use: [{ | ||||
| 					loader: 'vue-loader', | ||||
| 					options: { | ||||
| 						cssSourceMap: false, | ||||
| 						compilerOptions: { | ||||
| 							preserveWhitespace: false | ||||
| 						} | ||||
| if (isProduction) { | ||||
| 	plugins.push(new webpack.optimize.ModuleConcatenationPlugin()); | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
| 	entry, | ||||
| 	module: { | ||||
| 		rules: [{ | ||||
| 			test: /\.vue$/, | ||||
| 			exclude: /node_modules/, | ||||
| 			use: [{ | ||||
| 				loader: 'vue-loader', | ||||
| 				options: { | ||||
| 					cssSourceMap: false, | ||||
| 					compilerOptions: { | ||||
| 						preserveWhitespace: false | ||||
| 					} | ||||
| 				}, { | ||||
| 					loader: 'replace', | ||||
| 					query: { | ||||
| 						search: /%base64:(.+?)%/g.toString(), | ||||
| 						replace: 'base64replacement' | ||||
| 					} | ||||
| 				}, { | ||||
| 					loader: 'replace', | ||||
| 					query: { | ||||
| 						search: i18nReplacer.pattern.toString(), | ||||
| 						replace: 'i18nReplacement', | ||||
| 						i18n: true, | ||||
| 						lang | ||||
| 					} | ||||
| 				}, { | ||||
| 					loader: 'replace', | ||||
| 					query: { | ||||
| 						search: faPattern.toString(), | ||||
| 						replace: 'faReplacement' | ||||
| 					} | ||||
| 				}, { | ||||
| 					loader: 'replace', | ||||
| 					query: { | ||||
| 						search: /^<template>([\s\S]+?)\r?\n<\/template>/.toString(), | ||||
| 						replace: 'collapseSpacesReplacement' | ||||
| 					} | ||||
| 				}] | ||||
| 				} | ||||
| 			}, { | ||||
| 				test: /\.styl(us)?$/, | ||||
| 				exclude: /node_modules/, | ||||
| 				oneOf: [{ | ||||
| 					resourceQuery: /module/, | ||||
| 					use: [{ | ||||
| 						loader: 'vue-style-loader' | ||||
| 					}, { | ||||
| 						loader: 'css-loader', | ||||
| 						options: { | ||||
| 							modules: true, | ||||
| 							minimize: true | ||||
| 						} | ||||
| 					}, { | ||||
| 						loader: 'stylus-loader' | ||||
| 					}] | ||||
| 				}, { | ||||
| 					use: [{ | ||||
| 						loader: 'vue-style-loader' | ||||
| 					}, { | ||||
| 						loader: 'css-loader', | ||||
| 						options: { | ||||
| 							minimize: true | ||||
| 						} | ||||
| 					}, { | ||||
| 						loader: 'stylus-loader' | ||||
| 					}] | ||||
| 				}] | ||||
| 				loader: 'replace', | ||||
| 				query: { | ||||
| 					search: /%base64:(.+?)%/g.toString(), | ||||
| 					replace: 'base64replacement' | ||||
| 				} | ||||
| 			}, { | ||||
| 				test: /\.scss$/, | ||||
| 				exclude: /node_modules/, | ||||
| 				loader: 'replace', | ||||
| 				query: { | ||||
| 					search: i18nPattern.toString(), | ||||
| 					replace: 'i18nReplacement', | ||||
| 					i18n: true | ||||
| 				} | ||||
| 			}, { | ||||
| 				loader: 'replace', | ||||
| 				query: { | ||||
| 					search: faPattern.toString(), | ||||
| 					replace: 'faReplacement' | ||||
| 				} | ||||
| 			}, { | ||||
| 				loader: 'replace', | ||||
| 				query: { | ||||
| 					search: /^<template>([\s\S]+?)\r?\n<\/template>/.toString(), | ||||
| 					replace: 'collapseSpacesReplacement' | ||||
| 				} | ||||
| 			}] | ||||
| 		}, { | ||||
| 			test: /\.styl(us)?$/, | ||||
| 			exclude: /node_modules/, | ||||
| 			oneOf: [{ | ||||
| 				resourceQuery: /module/, | ||||
| 				use: [{ | ||||
| 					loader: 'style-loader' | ||||
| 					loader: 'vue-style-loader' | ||||
| 				}, { | ||||
| 					loader: 'css-loader', | ||||
| 					options: { | ||||
| 						modules: true, | ||||
| 						minimize: true | ||||
| 					} | ||||
| 				}, { | ||||
| 					loader: 'sass-loader', | ||||
| 					options: { | ||||
| 						importer: jsonImporter, | ||||
| 					} | ||||
| 					loader: 'stylus-loader' | ||||
| 				}] | ||||
| 			}, { | ||||
| 				test: /\.css$/, | ||||
| 				use: [{ | ||||
| 					loader: 'vue-style-loader' | ||||
| 				}, { | ||||
| @@ -221,52 +193,79 @@ module.exports = entries.map(x => { | ||||
| 					options: { | ||||
| 						minimize: true | ||||
| 					} | ||||
| 				}] | ||||
| 			}, { | ||||
| 				test: /\.(eot|woff|woff2|svg|ttf)([\?]?.*)$/, | ||||
| 				loader: 'url-loader' | ||||
| 			}, { | ||||
| 				test: /\.ts$/, | ||||
| 				exclude: /node_modules/, | ||||
| 				use: [{ | ||||
| 					loader: 'ts-loader', | ||||
| 					options: { | ||||
| 						happyPackMode: true, | ||||
| 						configFile: __dirname + '/src/client/app/tsconfig.json', | ||||
| 						appendTsSuffixTo: [/\.vue$/] | ||||
| 					} | ||||
| 				}, { | ||||
| 					loader: 'replace', | ||||
| 					query: { | ||||
| 						search: i18nReplacer.pattern.toString(), | ||||
| 						replace: 'i18nReplacement', | ||||
| 						i18n: true, | ||||
| 						lang | ||||
| 					} | ||||
| 				}, { | ||||
| 					loader: 'replace', | ||||
| 					query: { | ||||
| 						search: faPattern.toString(), | ||||
| 						replace: 'faReplacement' | ||||
| 					} | ||||
| 					loader: 'stylus-loader' | ||||
| 				}] | ||||
| 			}] | ||||
| 		}, | ||||
| 		plugins, | ||||
| 		output, | ||||
| 		resolve: { | ||||
| 			extensions: [ | ||||
| 				'.js', '.ts', '.json' | ||||
| 			], | ||||
| 			alias: { | ||||
| 				'const.styl': __dirname + '/src/client/const.styl' | ||||
| 			} | ||||
| 		}, | ||||
| 		resolveLoader: { | ||||
| 			modules: ['node_modules', './webpack/loaders'] | ||||
| 		}, | ||||
| 		cache: true, | ||||
| 		devtool: false, //'source-map', | ||||
| 		mode: isProduction ? 'production' : 'development' | ||||
| 	}; | ||||
| }); | ||||
| 		}, { | ||||
| 			test: /\.scss$/, | ||||
| 			exclude: /node_modules/, | ||||
| 			use: [{ | ||||
| 				loader: 'style-loader' | ||||
| 			}, { | ||||
| 				loader: 'css-loader', | ||||
| 				options: { | ||||
| 					minimize: true | ||||
| 				} | ||||
| 			}, { | ||||
| 				loader: 'sass-loader', | ||||
| 				options: { | ||||
| 					importer: jsonImporter, | ||||
| 				} | ||||
| 			}] | ||||
| 		}, { | ||||
| 			test: /\.css$/, | ||||
| 			use: [{ | ||||
| 				loader: 'vue-style-loader' | ||||
| 			}, { | ||||
| 				loader: 'css-loader', | ||||
| 				options: { | ||||
| 					minimize: true | ||||
| 				} | ||||
| 			}] | ||||
| 		}, { | ||||
| 			test: /\.(eot|woff|woff2|svg|ttf)([\?]?.*)$/, | ||||
| 			loader: 'url-loader' | ||||
| 		}, { | ||||
| 			test: /\.ts$/, | ||||
| 			exclude: /node_modules/, | ||||
| 			use: [{ | ||||
| 				loader: 'ts-loader', | ||||
| 				options: { | ||||
| 					happyPackMode: true, | ||||
| 					configFile: __dirname + '/src/client/app/tsconfig.json', | ||||
| 					appendTsSuffixTo: [/\.vue$/] | ||||
| 				} | ||||
| 			}, { | ||||
| 				loader: 'replace', | ||||
| 				query: { | ||||
| 					search: i18nPattern.toString(), | ||||
| 					replace: 'i18nReplacement', | ||||
| 					i18n: true | ||||
| 				} | ||||
| 			}, { | ||||
| 				loader: 'replace', | ||||
| 				query: { | ||||
| 					search: faPattern.toString(), | ||||
| 					replace: 'faReplacement' | ||||
| 				} | ||||
| 			}] | ||||
| 		}] | ||||
| 	}, | ||||
| 	plugins, | ||||
| 	output, | ||||
| 	resolve: { | ||||
| 		extensions: [ | ||||
| 			'.js', '.ts', '.json' | ||||
| 		], | ||||
| 		alias: { | ||||
| 			'const.styl': __dirname + '/src/client/const.styl' | ||||
| 		} | ||||
| 	}, | ||||
| 	resolveLoader: { | ||||
| 		modules: ['node_modules', './webpack/loaders'] | ||||
| 	}, | ||||
| 	cache: true, | ||||
| 	devtool: false, //'source-map', | ||||
| 	mode: isProduction ? 'production' : 'development' | ||||
| }; | ||||
|   | ||||
							
								
								
									
										24
									
								
								webpack/i18n.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								webpack/i18n.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| /** | ||||
|  * Replace i18n texts | ||||
|  */ | ||||
|  | ||||
| export const pattern = /%i18n:([a-z0-9_\-@\.\!]+?)%/g; | ||||
|  | ||||
| export const replacement = (ctx, match, key) => { | ||||
| 	const client = '/src/client/app/'; | ||||
| 	let name = null; | ||||
|  | ||||
| 	const shouldEscape = key[0] == '!'; | ||||
| 	if (shouldEscape) { | ||||
| 		key = key.substr(1); | ||||
| 	} | ||||
|  | ||||
| 	if (key[0] == '@') { | ||||
| 		name = ctx.src.substr(ctx.src.indexOf(client) + client.length); | ||||
| 		key = key.substr(1); | ||||
| 	} | ||||
|  | ||||
| 	const path = name ? `${name}|${key}` : key; | ||||
|  | ||||
| 	return shouldEscape ? `%i18n:!${path}%` : `%i18n:${path}%`; | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user
	 syuilo
					syuilo