From a465baf86dd4f14ef1118bcf0f91fa216e28c50c Mon Sep 17 00:00:00 2001 From: sharevb Date: Tue, 25 Jun 2024 09:06:53 +0200 Subject: [PATCH 1/3] feat(Lorem Ipsum Generator): generate multi language/script Fix #1080 --- components.d.ts | 2 + package.json | 2 + pnpm-lock.yaml | 51 ++++- src/composable/queryParams.ts | 33 ++- .../lorem-ipsum-generator/chinesegen.d.ts | 7 + .../lorem-ipsum-generator.service.ts | 214 +++--------------- .../lorem-ipsum-generator.vue | 19 +- .../lorem-ipsum-japanese.d.ts | 6 + .../lorem-ipsum.i18n.json | 208 +++++++++++++++++ 9 files changed, 348 insertions(+), 194 deletions(-) create mode 100644 src/tools/lorem-ipsum-generator/chinesegen.d.ts create mode 100644 src/tools/lorem-ipsum-generator/lorem-ipsum-japanese.d.ts create mode 100644 src/tools/lorem-ipsum-generator/lorem-ipsum.i18n.json diff --git a/components.d.ts b/components.d.ts index f2c3146f..920761d5 100644 --- a/components.d.ts +++ b/components.d.ts @@ -144,7 +144,9 @@ declare module '@vue/runtime-core' { NLayoutSider: typeof import('naive-ui')['NLayoutSider'] NMenu: typeof import('naive-ui')['NMenu'] NScrollbar: typeof import('naive-ui')['NScrollbar'] + NSlider: typeof import('naive-ui')['NSlider'] NSpin: typeof import('naive-ui')['NSpin'] + NSwitch: typeof import('naive-ui')['NSwitch'] NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] diff --git a/package.json b/package.json index c6cb7757..d7c7abac 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@vueuse/router": "^10.0.0", "bcryptjs": "^2.4.3", "change-case": "^4.1.2", + "chinesegen": "^0.3.3", "colord": "^2.9.3", "composerize-ts": "^0.6.2", "country-code-lookup": "^0.1.0", @@ -69,6 +70,7 @@ "jwt-decode": "^3.1.2", "libphonenumber-js": "^1.10.28", "lodash": "^4.17.21", + "lorem-ipsum-japanese": "^1.0.1", "marked": "^10.0.0", "mathjs": "^11.9.1", "mime-types": "^2.1.35", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8619d8c0..8cd0478d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,6 +47,9 @@ dependencies: change-case: specifier: ^4.1.2 version: 4.1.2 + chinesegen: + specifier: ^0.3.3 + version: 0.3.3 colord: specifier: ^2.9.3 version: 2.9.3 @@ -107,6 +110,9 @@ dependencies: lodash: specifier: ^4.17.21 version: 4.17.21 + lorem-ipsum-japanese: + specifier: ^1.0.1 + version: 1.0.1 marked: specifier: ^10.0.0 version: 10.0.0 @@ -3354,7 +3360,7 @@ packages: dependencies: '@unhead/dom': 0.5.1 '@unhead/schema': 0.5.1 - '@vueuse/shared': 10.8.0(vue@3.3.4) + '@vueuse/shared': 10.11.0(vue@3.3.4) unhead: 0.5.1 vue: 3.3.4 transitivePeerDependencies: @@ -3987,19 +3993,19 @@ packages: - vue dev: false - /@vueuse/shared@10.3.0(vue@3.3.4): - resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} + /@vueuse/shared@10.11.0(vue@3.3.4): + resolution: {integrity: sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==} dependencies: - vue-demi: 0.14.5(vue@3.3.4) + vue-demi: 0.14.8(vue@3.3.4) transitivePeerDependencies: - '@vue/composition-api' - vue dev: false - /@vueuse/shared@10.8.0(vue@3.3.4): - resolution: {integrity: sha512-dUdy6zwHhULGxmr9YUg8e+EnB39gcM4Fe2oKBSrh3cOsV30JcMPtsyuspgFCUo5xxFNaeMf/W2yyKfST7Bg8oQ==} + /@vueuse/shared@10.3.0(vue@3.3.4): + resolution: {integrity: sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==} dependencies: - vue-demi: 0.14.7(vue@3.3.4) + vue-demi: 0.14.5(vue@3.3.4) transitivePeerDependencies: - '@vue/composition-api' - vue @@ -4447,6 +4453,13 @@ packages: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true + /chinesegen@0.3.3: + resolution: {integrity: sha512-iwWTX4sPT8BwYaZr3SFr4D1tkToc1SXQ90AwnW8prCcGhv2nrOW38LStV27HtbHPUYTEhYbfG1KHoXRtqVBUFg==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -6720,6 +6733,13 @@ packages: is-unicode-supported: 0.1.0 dev: true + /lorem-ipsum-japanese@1.0.1: + resolution: {integrity: sha512-lL4XsigcYfSIsuUmHuoLB4wa71teS7XCx5tDgyZh6SoQmtwn0NTTMM54F69hy5aT8dkExH41hKmmOh1cET6I/w==} + hasBin: true + dependencies: + optimist: 0.3.7 + dev: false + /loupe@2.3.6: resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} dependencies: @@ -6932,7 +6952,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /mlly@1.4.0: resolution: {integrity: sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==} @@ -7179,6 +7198,12 @@ packages: is-wsl: 2.2.0 dev: true + /optimist@0.3.7: + resolution: {integrity: sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==} + dependencies: + wordwrap: 0.0.3 + dev: false + /optionator@0.9.3: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} @@ -9158,8 +9183,8 @@ packages: vue: 3.3.4 dev: false - /vue-demi@0.14.7(vue@3.3.4): - resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==} + /vue-demi@0.14.8(vue@3.3.4): + resolution: {integrity: sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==} engines: {node: '>=12'} hasBin: true requiresBuild: true @@ -9371,6 +9396,11 @@ packages: stackback: 0.0.2 dev: true + /wordwrap@0.0.3: + resolution: {integrity: sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==} + engines: {node: '>=0.4.0'} + dev: false + /workbox-background-sync@7.0.0: resolution: {integrity: sha512-S+m1+84gjdueM+jIKZ+I0Lx0BDHkk5Nu6a3kTVxP4fdj3gKouRNmhO8H290ybnJTOPfBDtTMXSQA/QLTvr7PeA==} dependencies: @@ -9449,6 +9479,7 @@ packages: /workbox-google-analytics@7.0.0: resolution: {integrity: sha512-MEYM1JTn/qiC3DbpvP2BVhyIH+dV/5BjHk756u9VbwuAhu0QHyKscTnisQuz21lfRpOwiS9z4XdqeVAKol0bzg==} + deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained dependencies: workbox-background-sync: 7.0.0 workbox-core: 7.0.0 diff --git a/src/composable/queryParams.ts b/src/composable/queryParams.ts index 9699abbc..7cc8cc0d 100644 --- a/src/composable/queryParams.ts +++ b/src/composable/queryParams.ts @@ -1,7 +1,8 @@ import { useRouteQuery } from '@vueuse/router'; import { computed } from 'vue'; +import { useStorage } from '@vueuse/core'; -export { useQueryParam }; +export { useQueryParam, useQueryParamOrStorage }; const transformers = { number: { @@ -16,6 +17,12 @@ const transformers = { fromQuery: (value: string) => value.toLowerCase() === 'true', toQuery: (value: boolean) => (value ? 'true' : 'false'), }, + object: { + fromQuery: (value: string) => { + return JSON.parse(value); + }, + toQuery: (value: object) => JSON.stringify(value), + }, }; function useQueryParam({ name, defaultValue }: { name: string; defaultValue: T }) { @@ -33,3 +40,27 @@ function useQueryParam({ name, defaultValue }: { name: string; defaultValue: }, }); } + +function useQueryParamOrStorage({ name, storageName, defaultValue }: { name: string; storageName: string; defaultValue: T }) { + const type = typeof defaultValue; + const transformer = transformers[type as keyof typeof transformers] ?? transformers.string; + + const storageRef = useStorage(storageName, defaultValue); + const proxyDefaultValue = transformer.toQuery(defaultValue as never); + const proxy = useRouteQuery(name, proxyDefaultValue); + + const r = ref(defaultValue); + + watch(r, + (value) => { + proxy.value = transformer.toQuery(value as never); + storageRef.value = value as never; + }, + { deep: true }); + + r.value = (proxy.value && proxy.value !== proxyDefaultValue + ? transformer.fromQuery(proxy.value) as unknown as T + : storageRef.value as T) as never; + + return r; +} diff --git a/src/tools/lorem-ipsum-generator/chinesegen.d.ts b/src/tools/lorem-ipsum-generator/chinesegen.d.ts new file mode 100644 index 00000000..d777428b --- /dev/null +++ b/src/tools/lorem-ipsum-generator/chinesegen.d.ts @@ -0,0 +1,7 @@ +declare module 'chinesegen' { + export default function lorem(config: { + count: number, + }): { + text: string + }; +} \ No newline at end of file diff --git a/src/tools/lorem-ipsum-generator/lorem-ipsum-generator.service.ts b/src/tools/lorem-ipsum-generator/lorem-ipsum-generator.service.ts index b21a302b..c7a67985 100644 --- a/src/tools/lorem-ipsum-generator/lorem-ipsum-generator.service.ts +++ b/src/tools/lorem-ipsum-generator/lorem-ipsum-generator.service.ts @@ -1,185 +1,39 @@ +import _ from 'lodash'; +import loremIpsumJapanese from 'lorem-ipsum-japanese'; +import chinesegen from 'chinesegen'; +import languageLorems from './lorem-ipsum.i18n.json'; import { randFromArray } from '@/utils/random'; -const vocabulary = [ - 'a', - 'ac', - 'accumsan', - 'ad', - 'adipiscing', - 'aenean', - 'aliquam', - 'aliquet', - 'amet', - 'ante', - 'aptent', - 'arcu', - 'at', - 'auctor', - 'bibendum', - 'blandit', - 'class', - 'commodo', - 'condimentum', - 'congue', - 'consectetur', - 'consequat', - 'conubia', - 'convallis', - 'cras', - 'cubilia', - 'cum', - 'curabitur', - 'curae', - 'dapibus', - 'diam', - 'dictum', - 'dictumst', - 'dignissim', - 'dolor', - 'donec', - 'dui', - 'duis', - 'egestas', - 'eget', - 'eleifend', - 'elementum', - 'elit', - 'enim', - 'erat', - 'eros', - 'est', - 'et', - 'etiam', - 'eu', - 'euismod', - 'facilisi', - 'faucibus', - 'felis', - 'fermentum', - 'feugiat', - 'fringilla', - 'fusce', - 'gravida', - 'habitant', - 'habitasse', - 'hac', - 'hendrerit', - 'himenaeos', - 'iaculis', - 'id', - 'imperdiet', - 'in', - 'inceptos', - 'integer', - 'interdum', - 'ipsum', - 'justo', - 'lacinia', - 'lacus', - 'laoreet', - 'lectus', - 'leo', - 'ligula', - 'litora', - 'lobortis', - 'lorem', - 'luctus', - 'maecenas', - 'magna', - 'magnis', - 'malesuada', - 'massa', - 'mattis', - 'mauris', - 'metus', - 'mi', - 'molestie', - 'mollis', - 'montes', - 'morbi', - 'mus', - 'nam', - 'nascetur', - 'natoque', - 'nec', - 'neque', - 'netus', - 'nisi', - 'nisl', - 'non', - 'nostra', - 'nulla', - 'nullam', - 'nunc', - 'odio', - 'orci', - 'ornare', - 'parturient', - 'pellentesque', - 'penatibus', - 'per', - 'pharetra', - 'phasellus', - 'placerat', - 'platea', - 'porta', - 'porttitor', - 'posuere', - 'potenti', - 'praesent', - 'pretium', - 'primis', - 'proin', - 'pulvinar', - 'purus', - 'quam', - 'quis', - 'quisque', - 'rhoncus', - 'ridiculus', - 'risus', - 'rutrum', - 'sagittis', - 'sapien', - 'scelerisque', - 'sed', - 'sem', - 'semper', - 'senectus', - 'sit', - 'sociis', - 'sociosqu', - 'sodales', - 'sollicitudin', - 'suscipit', - 'suspendisse', - 'taciti', - 'tellus', - 'tempor', - 'tempus', - 'tincidunt', - 'torquent', - 'tortor', - 'turpis', - 'ullamcorper', - 'ultrices', - 'ultricies', - 'urna', - 'varius', - 'vehicula', - 'vel', - 'velit', - 'venenatis', - 'vestibulum', - 'vitae', - 'vivamus', - 'viverra', - 'volutpat', - 'vulputate', -]; const firstSentence = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'; -function generateSentence(length: number) { +export function getSupportedLanguages() { + return _.union( + _.flatten(_.chain(languageLorems).map(l => l.languages).value()), + ['Japanese', 'Chinese']) + .sort(); +} + +function generateSentence(language: string, length: number) { + if (language === 'Japanese') { + return loremIpsumJapanese({ + count: length, + units: 'words', + }); + } + if (language === 'Chinese') { + return chinesegen({ count: length }).text; + } + + if (language === 'Emoticon') { + const loremIcons = _.find(languageLorems, ({ languages }) => languages.includes(language))?.loremIpsum || ''; + const iconsChars = [...loremIcons]; + return Array.from({ length }) + .map(() => randFromArray(iconsChars)) + .join(' '); + } + + const vocabulary = _.find(languageLorems, ({ languages }) => languages.includes(language))?.loremIpsum?.split(' ') || []; + const sentence = Array.from({ length }) .map(() => randFromArray(vocabulary)) .join(' '); @@ -193,15 +47,17 @@ export function generateLoremIpsum({ wordCount = 10, startWithLoremIpsum = true, asHTML = false, + language = 'English', }: { paragraphCount?: number sentencePerParagraph?: number wordCount?: number startWithLoremIpsum?: boolean asHTML?: boolean + language?: string }) { const paragraphs = Array.from({ length: paragraphCount }).map(() => - Array.from({ length: sentencePerParagraph }).map(() => generateSentence(wordCount)), + Array.from({ length: sentencePerParagraph }).map(() => generateSentence(language, wordCount)), ); if (startWithLoremIpsum) { diff --git a/src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue b/src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue index 9085725f..e3007f27 100644 --- a/src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue +++ b/src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue @@ -1,14 +1,17 @@