From 06b77225b832741aa03093f8d126d121b4127825 Mon Sep 17 00:00:00 2001 From: fmdm Date: Fri, 7 Jun 2024 15:59:08 +0300 Subject: [PATCH] flags solved --- .npmignore | 3 +- docs/README.md | 14 +------- docs/bonus.md | 54 +++++++++++++++++++++++++++++ package.json | 4 +-- src/client.ts | 12 ++++++- src/s-a.ts | 4 ++- src/server-shared/client.ts | 9 ----- src/server-shared/s-a.ts | 3 -- src/server.ts | 2 +- src/tools/flags.ts | 69 +++++++++++++++++++++++++++++++++---- test/specifics.test.ts | 4 +-- 11 files changed, 138 insertions(+), 40 deletions(-) create mode 100644 docs/bonus.md delete mode 100644 src/server-shared/client.ts delete mode 100644 src/server-shared/s-a.ts diff --git a/.npmignore b/.npmignore index eed20eb..e71a007 100644 --- a/.npmignore +++ b/.npmignore @@ -6,4 +6,5 @@ *.config.js *.config.json .gitignore -/.svelte-kit \ No newline at end of file +/.svelte-kit +package-lock.json \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 7f0cffa..9b60043 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,16 +11,4 @@ Projects using OmnI18n use it in 4 layers The library can be imported in a [static website](umd.md). -## Bonus - -### Flags - -Just realized it was [not working on windows](https://answers.microsoft.com/en-us/windows/forum/all/flag-emoji/85b163bc-786a-4918-9042-763ccf4b6c05)... - -```js -import { localeFlags, flagCodeExceptions } -localeFlags('en-GB') // ['🇬🇧'] -localeFlags('en-US') //['🇬🇧', '🇺🇸'] -flagCodeExceptions.en = '🏴󠁧󠁢󠁥󠁮󠁧󠁿' -localeFlags('en-GB') // ['🏴󠁧󠁢󠁥󠁮󠁧󠁿', '🇬🇧'] -``` +There are [some utils that have been done for the library](./bonus.md) and are exported with it (flags, js-like json & defer) diff --git a/docs/bonus.md b/docs/bonus.md new file mode 100644 index 0000000..3b0cb17 --- /dev/null +++ b/docs/bonus.md @@ -0,0 +1,54 @@ +# Bonuses + +## Flags + +The library takes in consideration two cases: + +- On systems who support flags emojis, flags will just be this, a 2~3 unicode characters that form the emoji +- On windows, the library `flag-icons` will be downloaded dynamically from [cdnjs.com](https://cdnjs.com/libraries/flag-icon-css) (~28k) and `localeFlag` will return a ` `gb`) + +> Note: under windows, you won't see flags here beside '🏴󠁧󠁢󠁥󠁮󠁧󠁿' who is not even the correct one. + +```js +import { localeFlags, flagCodeExceptions } +localeFlags('en-GB') // ['🇬🇧'] +localeFlags('en-US') //['🇬🇧', '🇺🇸'] +flagEmojiExceptions.en = '🏴󠁧󠁢󠁥󠁮󠁧󠁿' +flagClassExceptions.en = 'gb-eng' +localeFlags('en-GB') // ['🏴󠁧󠁢󠁥󠁮󠁧󠁿', '🇬🇧'] +``` + +> Note: The returned strings must therefore be considered as html code, not pure text, even if for most, it will be pure text + +## js-like "jsonability" + +The dictionary uses a human "json" format. It's really minimalistic and didn't deserve the 25k of `json5` or `hjson`, it doesn't have more ability than json but: + +- allows js-like comment +- uses indifferently <">, <'>, or <`> as quote markers +- does not need quotes for keys + +The main difference with JavaScript is that all quotes behave the same than <`> for new lines: + +``` +{ + myMultilineString: "Hello +here" +} +``` + +The library exports the 2 functions `parse` and `stringify`. + +The `maxLength` (2nd argument of `stringify`) specifies the maximum length an object/array can have on a line. When it exceeds this limit, the object/array is described with one line per element. + +## Defer + +The defer class allows to plan an action "on next tick" but let the code finish its modifications before actually doing it. + +The callback can be given on constructor or when calling `.defer(...)` + +You can get its `.promise` to wait (or `then`), get its instant `.deferring` status (boolean) or forcefully `.cancel()` or `.resolve()` diff --git a/package.json b/package.json index fd1e8ac..c193018 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omni18n", - "version": "1.1.11", + "version": "1.1.12", "exports": { ".": { "browser": { @@ -37,7 +37,7 @@ "build": "rollup -c", "build-umd": "rollup -c rollup.umd.js --watch", "build-extract": "rollup -c rollup.extract.js", - "prepare": "npm run prettier && npm run build" + "prepack": "npm run prettier && npm run build" }, "repository": { "type": "git", diff --git a/src/client.ts b/src/client.ts index cd35547..c5de9e9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,2 +1,12 @@ -export * from './server-shared/client' +export * from './types' +export * from './client/index' +export * from './tools/cgpt-js' export * from './tools/flags' +import { default as Defer } from './tools/defer' +export { Defer } + +declare global { + interface Set { + union(...sets: Set[]): this + } +} diff --git a/src/s-a.ts b/src/s-a.ts index f9b87b5..4a07569 100644 --- a/src/s-a.ts +++ b/src/s-a.ts @@ -1,2 +1,4 @@ -export * from './server-shared/s-a' +export * from './client' +export * from './server/index' +export * from './db/index' export * from './tools/flags' diff --git a/src/server-shared/client.ts b/src/server-shared/client.ts deleted file mode 100644 index f0caffe..0000000 --- a/src/server-shared/client.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from '../types' -export * from '../client/index' -export * from '../tools/cgpt-js' - -declare global { - interface Set { - union(...sets: Set[]): this - } -} diff --git a/src/server-shared/s-a.ts b/src/server-shared/s-a.ts deleted file mode 100644 index e33a5c9..0000000 --- a/src/server-shared/s-a.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './client' -export * from '../server/index' -export * from '../db/index' diff --git a/src/server.ts b/src/server.ts index 29f2886..3777ee5 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,3 +1,3 @@ -export * from './server-shared/s-a' +export * from './s-a' import FileDB from './db/fileDb' export { FileDB } diff --git a/src/tools/flags.ts b/src/tools/flags.ts index 837d45a..b3ca3e2 100644 --- a/src/tools/flags.ts +++ b/src/tools/flags.ts @@ -1,21 +1,76 @@ import { Locale } from '../types' -function toEmoji(name: string) { - return String.fromCodePoint(...Array.from(name).map((k) => k.charCodeAt(0) + 127365)) -} - /** * Some language codes do not have a clear country code and should be indicated here * * https://emojipedia.org/flags */ -export const flagCodeExceptions: Record = { en: '🇬🇧' } +export const flagEmojiExceptions: Record = { en: '🇬🇧' } +export const flagClassExceptions: Record = { en: 'gb' } + +const styleSheet = `` + +export let flagEngine: 'emojis' | 'flag-icons' +export let headStyle: string = '' +flagEngine = 'emojis' // Do not initialize on declaration, rollup considers it as a constant + +export function setFlagEngine(engine: 'emojis' | 'flag-icons') { + flagEngine = engine + headStyle = engine === 'flag-icons' ? styleSheet : '' + if (engine === 'flag-icons' && typeof window !== undefined) { + let alreadyHasStyleSheet = false + //const stylesheets = document.querySelectorAll('link[rel="stylesheet"][href*="/flag-icons."]') + const stylesheets = document.querySelectorAll('link[rel="stylesheet"]') + for (let i = 0; i < stylesheets.length; i++) { + if (stylesheets[i].getAttribute('href')?.includes('/flag-icons.')) { + alreadyHasStyleSheet = true + break + } + } + if (!alreadyHasStyleSheet) document.head.insertAdjacentHTML('beforeend', styleSheet) + } +} + +if (typeof navigator !== 'undefined') gotUserAgent(navigator.userAgent) + +/** + * Set the global flag engine based on the user agent + * @param userAgent The kind of string returned by `navigator.userAgent` or given in the `user-agent` request header + */ +export function gotUserAgent(userAgent: string) { + if (userAgent.toLowerCase().includes('windows')) setFlagEngine('flag-icons') +} -export function localeFlags(locale: Locale) { +function localeFlagsEmojis(locale: Locale) { const parts = locale .toLowerCase() .split('-', 3) .slice(0, 2) - .map((code) => flagCodeExceptions[code] || toEmoji(code)) + .map( + (code) => + flagEmojiExceptions[code] || + String.fromCodePoint(...Array.from(code).map((k) => k.charCodeAt(0) + 127365)) + ) + return parts[0] === parts[1] ? [parts[0]] : parts +} + +function localeFlagsIcons(locale: Locale) { + function createSpan(code: string) { + return `` + } + const parts = locale + .toLowerCase() + .split('-', 2) + .map((code) => createSpan(flagClassExceptions[code] || code)) return parts[0] === parts[1] ? [parts[0]] : parts } + +/** + * Gets one or two html strings representing the flags for the given locale (2 in case of `en-US` for example) + * @param locale The locale + * @param engine Optional: specify wether the targeted system is windows or not (if not, just use emojis) + * @returns + */ +export function localeFlags(locale: Locale, engine?: 'emojis' | 'flag-icons'): string[] { + return (engine ?? flagEngine) === 'emojis' ? localeFlagsEmojis(locale) : localeFlagsIcons(locale) +} diff --git a/test/specifics.test.ts b/test/specifics.test.ts index b6d5646..d575d5b 100644 --- a/test/specifics.test.ts +++ b/test/specifics.test.ts @@ -10,7 +10,7 @@ import { bulkObject, reports, localeFlags, - flagCodeExceptions, + flagEmojiExceptions, parse, stringify } from '~/s-a' @@ -91,7 +91,7 @@ describe('specifics', () => { expect(localeFlags('en')).toEqual(['🇬🇧']) expect(localeFlags('en-GB')).toEqual(['🇬🇧']) expect(localeFlags('en-US-gb')).toEqual(['🇬🇧', '🇺🇸']) - flagCodeExceptions.en = '🏴󠁧󠁢󠁥󠁮󠁧󠁿' + flagEmojiExceptions.en = '🏴󠁧󠁢󠁥󠁮󠁧󠁿' expect(localeFlags('en-GB')).toEqual(['🏴󠁧󠁢󠁥󠁮󠁧󠁿', '🇬🇧']) expect(localeFlags('fr')).toEqual(['🇫🇷']) expect(localeFlags('fr-FR')).toEqual(['🇫🇷'])