diff --git a/packages/frontend/src/scripts/nyaize.ts b/packages/frontend/src/scripts/nyaize.ts index abc8ada461..58ed88fed1 100644 --- a/packages/frontend/src/scripts/nyaize.ts +++ b/packages/frontend/src/scripts/nyaize.ts @@ -3,21 +3,26 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -const enRegex1 = /(?<=n)a/gi; -const enRegex2 = /(?<=morn)ing/gi; -const enRegex3 = /(?<=every)one/gi; const koRegex1 = /[나-낳]/g; const koRegex2 = /(다$)|(다(?=\.))|(다(?= ))|(다(?=!))|(다(?=\?))/gm; const koRegex3 = /(야(?=\?))|(야$)|(야(?= ))/gm; +function ifAfter(prefix, fn) { + const preLen = prefix.length; + const regex = new RegExp(prefix,'i'); + return (x,pos,string) => { + return pos > 0 && string.substring(pos-preLen,pos).match(regex) ? fn(x) : x; + }; +} + export function nyaize(text: string): string { return text // ja-JP .replaceAll('な', 'にゃ').replaceAll('ナ', 'ニャ').replaceAll('ナ', 'ニャ') // en-US - .replace(enRegex1, x => x === 'A' ? 'YA' : 'ya') - .replace(enRegex2, x => x === 'ING' ? 'YAN' : 'yan') - .replace(enRegex3, x => x === 'ONE' ? 'NYAN' : 'nyan') + .replace(/a/gi, ifAfter('n', x => x === 'A' ? 'YA' : 'ya')) + .replace(/ing/gi, ifAfter('morn', x => x === 'ING' ? 'YAN' : 'yan')) + .replace(/one/gi, ifAfter('every', x => x === 'ONE' ? 'NYAN' : 'nyan')) // ko-KR .replace(koRegex1, match => String.fromCharCode( match.charCodeAt(0)! + '냐'.charCodeAt(0) - '나'.charCodeAt(0), diff --git a/packages/frontend/test/nyaize.test.ts b/packages/frontend/test/nyaize.test.ts new file mode 100644 index 0000000000..d4f0fff1db --- /dev/null +++ b/packages/frontend/test/nyaize.test.ts @@ -0,0 +1,32 @@ +import { describe, test, assert, afterEach } from 'vitest'; +import { nyaize } from '@/scripts/nyaize.js'; + +function runTests(cases) { + for (const c of cases) { + const [input,expected] = c; + const got = nyaize(input); + assert.strictEqual(got, expected); + } +} + +describe('nyaize', () => { + test('ja-JP', () => { + runTests([ + ['きれいな','きれいにゃ'], + ['ナナナ', 'ニャニャニャ'], + ['ナナ','ニャニャ'], + ]); + }); + test('en-US', () => { + runTests([ + ['bar','bar'], + ['banana','banyanya'], + ['booting','booting'], + ['morning','mornyan'], + ['mmmorning','mmmornyan'], + ['someone','someone'], + ['everyone','everynyan'], + ['foreveryone','foreverynyan'], + ]); + }); +});