@nanostores/i18n
Advanced tools
Comparing version 0.9.0 to 0.10.0
@@ -1,2 +0,2 @@ | ||
import { ReadableAtom } from 'nanostores' | ||
import type { ReadableAtom } from 'nanostores' | ||
@@ -3,0 +3,0 @@ type AutodetectOpts<Locales extends readonly string[]> = Extract< |
@@ -1,2 +0,2 @@ | ||
import { | ||
import type { | ||
TranslationJSON, | ||
@@ -3,0 +3,0 @@ TranslationFunction, |
@@ -1,6 +0,5 @@ | ||
import { ReadableAtom } from 'nanostores' | ||
import type { ReadableAtom } from 'nanostores' | ||
import type { LocaleStore } from '../locale-from/index.js' | ||
import type { Processor } from '../processor/index.js' | ||
import { LocaleStore } from '../locale-from/index.js' | ||
import { Processor } from '../processor/index.js' | ||
export type TranslationJSON = string | TranslationsJSON | ||
@@ -85,3 +84,3 @@ | ||
baseLocale?: BaseLocale | ||
cache?: Record<Locale, Translations> | ||
cache?: Record<Locale, Components> | ||
get: TranslationLoader<Locale> | ||
@@ -88,0 +87,0 @@ processors?: Processor[] |
@@ -1,2 +0,2 @@ | ||
import { atom, onMount } from 'nanostores' | ||
import { atom, onMount, computed } from 'nanostores' | ||
@@ -6,6 +6,37 @@ export function createI18n(locale, opts) { | ||
let processors = opts.processors || [] | ||
let loading = atom(true) | ||
let loadedLocale = atom(baseLocale) | ||
let mounted = new Set() | ||
let requested = new Set() | ||
async function getTranslation(code, components) { | ||
let newComponents = [] | ||
let newPrefixes = [] | ||
for (let name of components) { | ||
let prefix = name.split('/')[0] | ||
if (!requested.has(prefix)) { | ||
newComponents.push(name) | ||
newPrefixes.push(prefix) | ||
} | ||
} | ||
if (newComponents.length === 0) return | ||
loadedLocale.set(false) | ||
for (let prefix of newPrefixes) requested.add(prefix) | ||
let translations = await opts.get(code, newComponents) | ||
if (Array.isArray(translations)) { | ||
translations = translations.reduce((obj, item) => | ||
Object.assign(obj, item) | ||
) | ||
} | ||
define.cache[code] = { ...define.cache[code], ...translations } | ||
for (let name in translations) { | ||
let prefix = name.split('/')[0] | ||
requested.delete(prefix) | ||
} | ||
if (code === locale.get() && requested.size === 0) { | ||
loadedLocale.set(code) | ||
} | ||
} | ||
let define = (componentName, base) => { | ||
@@ -58,4 +89,9 @@ let transforms = {} | ||
} | ||
setTranslation(baseLocale) | ||
if (locale.get() !== baseLocale && define.cache[locale.get()]) { | ||
setTranslation(locale.get()) | ||
} else { | ||
setTranslation(baseLocale) | ||
} | ||
onMount(t, () => { | ||
@@ -70,9 +106,3 @@ mounted.add(componentName) | ||
} else { | ||
let prefix = componentName.split('/')[0] | ||
if (!requested.has(prefix)) { | ||
requested.add(prefix) | ||
getTranslation(code, [componentName]).then(() => { | ||
requested.delete(prefix) | ||
}) | ||
} | ||
getTranslation(code, [componentName]) | ||
} | ||
@@ -84,10 +114,8 @@ for (let i in processors) { | ||
} | ||
let unbindLoading = loading.listen(isLoading => { | ||
if (!isLoading) { | ||
setTranslation(locale.get()) | ||
} | ||
let unbindLoaded = loadedLocale.listen(loaded => { | ||
if (loaded) setTranslation(loaded) | ||
}) | ||
return () => { | ||
mounted.delete(componentName) | ||
unbindLoading() | ||
unbindLoaded() | ||
} | ||
@@ -102,29 +130,19 @@ }) | ||
} | ||
define.loading = loading | ||
define.loading = computed([locale, loadedLocale], (current, loaded) => { | ||
return current !== loaded | ||
}) | ||
async function getTranslation(code, components) { | ||
loading.set(true) | ||
let translations = await opts.get(code, components) | ||
if (Array.isArray(translations)) { | ||
translations = translations.reduce((obj, item) => | ||
Object.assign(obj, item) | ||
) | ||
} | ||
define.cache[code] = { ...define.cache[code], ...translations } | ||
if (code === locale.get()) loading.set(false) | ||
} | ||
locale.listen(code => { | ||
locale.subscribe(code => { | ||
let nonCached = Array.from(mounted).filter( | ||
component => !(define.cache[code] && define.cache[code][component]) | ||
) | ||
requested.clear() | ||
if (nonCached.length) { | ||
getTranslation(code, nonCached) | ||
} else { | ||
loading.set(false) | ||
loadedLocale.set(code) | ||
} | ||
}) | ||
loading.set(false) | ||
return define | ||
} |
@@ -1,5 +0,4 @@ | ||
import { ReadableAtom } from 'nanostores' | ||
import type { ReadableAtom } from 'nanostores' | ||
import type { LocaleStore } from '../locale-from/index.js' | ||
import { LocaleStore } from '../locale-from/index.js' | ||
export interface Formatter { | ||
@@ -6,0 +5,0 @@ number(num: number, opts?: Intl.NumberFormatOptions): string |
@@ -1,2 +0,2 @@ | ||
import { ReadableAtom, Atom } from 'nanostores' | ||
import type { ReadableAtom, Atom } from 'nanostores' | ||
@@ -3,0 +3,0 @@ export type LocaleStore<Locale extends string = string> = ReadableAtom<Locale> |
@@ -1,2 +0,2 @@ | ||
import { Messages, ComponentsJSON } from '../create-i18n/index.js' | ||
import type { Messages, ComponentsJSON } from '../create-i18n/index.js' | ||
@@ -3,0 +3,0 @@ /** |
{ | ||
"name": "@nanostores/i18n", | ||
"version": "0.9.0", | ||
"description": "A tiny (≈600 bytes) i18n library for React/Preact/Vue/Svelte", | ||
"version": "0.10.0", | ||
"description": "A tiny (≈700 bytes) i18n library for React/Preact/Vue/Svelte", | ||
"keywords": [ | ||
@@ -27,3 +27,3 @@ "nano", | ||
"engines": { | ||
"node": "^16.0.0 || >=18.0.0" | ||
"node": "^16.0.0 || ^18.0.0 || >=20.0.0" | ||
}, | ||
@@ -37,4 +37,4 @@ "funding": [ | ||
"peerDependencies": { | ||
"nanostores": "^0.8.0" | ||
"nanostores": "^0.9.0" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
import { | ||
import type { | ||
TranslationFunctionAlternatives, | ||
@@ -3,0 +3,0 @@ TranslationFunction |
@@ -1,5 +0,7 @@ | ||
import { ReadableAtom } from 'nanostores' | ||
import type { ReadableAtom } from 'nanostores' | ||
import type { | ||
TranslationJSON, | ||
TranslationFunction | ||
} from '../create-i18n/index.js' | ||
import { TranslationJSON, TranslationFunction } from '../create-i18n/index.js' | ||
export interface Processor<Key extends string = string> { | ||
@@ -6,0 +8,0 @@ from: ReadableAtom<Key> |
@@ -9,7 +9,6 @@ # Nano Stores I18n | ||
* **Small.** Between 654 and 1088 bytes (minified and gzipped). | ||
Zero dependencies. | ||
* **Small.** Around 1 KB (minified and gzipped). Zero dependencies. | ||
* Works with **React**, **Preact**, **Vue**, **Svelte**, and plain JS. | ||
* Supports **tree-shaking** and translation **on-demand download**. | ||
* **Plain JSON** translations compatible with | ||
* **Plain flat JSON** translations compatible with | ||
online translation services like [Weblate]. | ||
@@ -28,3 +27,4 @@ * Out of the box **TypeScript** support for translations. | ||
title: 'Post details', | ||
published: params<{ at: string }>('Was published at {at}') | ||
// You need to manually mark interpolation like {at} for better TS support | ||
published: params<{ at: string }>('Was published at {at}'), | ||
comments: count({ | ||
@@ -50,7 +50,12 @@ one: '{count} comment', | ||
import { createI18n, localeFrom, browser, formatter } from '@nanostores/i18n' | ||
import localeSettings from './locale-settings.js' | ||
import { persistentAtom } from '@nanostores/persistent' | ||
export const setting = persistentAtom<string | undefined>('locale', undefined) | ||
export const locale = localeFrom( | ||
localeSettings, // User’s locale from localStorage | ||
browser({ available: ['en', 'fr', 'ru'] }) // or browser’s locale auto-detect | ||
setting, // User’s locale from localStorage | ||
browser({ // or browser’s locale auto-detect | ||
available: ['en', 'fr', 'ru'], | ||
fallback: 'en' | ||
}) | ||
) | ||
@@ -57,0 +62,0 @@ |
@@ -1,2 +0,5 @@ | ||
import { TranslationFunction, TranslationJSON } from '../create-i18n/index.js' | ||
import type { | ||
TranslationFunction, | ||
TranslationJSON | ||
} from '../create-i18n/index.js' | ||
@@ -3,0 +6,0 @@ export type TranslationTransform< |
@@ -1,2 +0,2 @@ | ||
import { I18n } from '../create-i18n/index.js' | ||
import type { I18n } from '../create-i18n/index.js' | ||
@@ -3,0 +3,0 @@ /** |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24772
691
97