diff options
Diffstat (limited to 'src/client/scripts')
| -rw-r--r-- | src/client/scripts/i18n.ts | 44 | ||||
| -rw-r--r-- | src/client/scripts/initialize-sw.ts | 68 |
2 files changed, 112 insertions, 0 deletions
diff --git a/src/client/scripts/i18n.ts b/src/client/scripts/i18n.ts new file mode 100644 index 0000000000..d535e236bb --- /dev/null +++ b/src/client/scripts/i18n.ts @@ -0,0 +1,44 @@ +// Notice: Service Workerでも使用します +export class I18n<T extends Record<string, any>> { + public locale: T; + + constructor(locale: T) { + this.locale = locale; + + if (_DEV_) { + console.log('i18n', this.locale); + } + + //#region BIND + this.t = this.t.bind(this); + //#endregion + } + + // string にしているのは、ドット区切りでのパス指定を許可するため + // なるべくこのメソッド使うよりもlocale直接参照の方がvueのキャッシュ効いてパフォーマンスが良いかも + public t(key: string, args?: Record<string, any>): string { + try { + let str = key.split('.').reduce((o, i) => o[i], this.locale) as string; + + if (_DEV_) { + if (!str.includes('{')) { + console.warn(`i18n: '${key}' has no any arg. so ref prop directly instead of call this method.`); + } + } + + if (args) { + for (const [k, v] of Object.entries(args)) { + str = str.replace(`{${k}}`, v); + } + } + return str; + } catch (e) { + if (_DEV_) { + console.warn(`missing localization '${key}'`); + return `⚠'${key}'⚠`; + } + + return key; + } + } +} diff --git a/src/client/scripts/initialize-sw.ts b/src/client/scripts/initialize-sw.ts new file mode 100644 index 0000000000..d6dbd5dbd4 --- /dev/null +++ b/src/client/scripts/initialize-sw.ts @@ -0,0 +1,68 @@ +import { instance } from '@/instance'; +import { $i } from '@/account'; +import { api } from '@/os'; +import { lang } from '@/config'; + +export async function initializeSw() { + if (instance.swPublickey && + ('serviceWorker' in navigator) && + ('PushManager' in window) && + $i && $i.token) { + navigator.serviceWorker.register(`/sw.js`); + + navigator.serviceWorker.ready.then(registration => { + registration.active?.postMessage({ + msg: 'initialize', + lang, + }); + // SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters + registration.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: urlBase64ToUint8Array(instance.swPublickey) + }).then(subscription => { + function encode(buffer: ArrayBuffer | null) { + return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer))); + } + + // Register + api('sw/register', { + endpoint: subscription.endpoint, + auth: encode(subscription.getKey('auth')), + publickey: encode(subscription.getKey('p256dh')) + }); + }) + // When subscribe failed + .catch(async (err: Error) => { + // 通知が許可されていなかったとき + if (err.name === 'NotAllowedError') { + return; + } + + // 違うapplicationServerKey (または gcm_sender_id)のサブスクリプションが + // 既に存在していることが原因でエラーになった可能性があるので、 + // そのサブスクリプションを解除しておく + const subscription = await registration.pushManager.getSubscription(); + if (subscription) subscription.unsubscribe(); + }); + }); + } +} + +/** + * Convert the URL safe base64 string to a Uint8Array + * @param base64String base64 string + */ +function urlBase64ToUint8Array(base64String: string): Uint8Array { + const padding = '='.repeat((4 - base64String.length % 4) % 4); + const base64 = (base64String + padding) + .replace(/-/g, '+') + .replace(/_/g, '/'); + + const rawData = window.atob(base64); + const outputArray = new Uint8Array(rawData.length); + + for (let i = 0; i < rawData.length; ++i) { + outputArray[i] = rawData.charCodeAt(i); + } + return outputArray; +} |