-
-
Notifications
You must be signed in to change notification settings - Fork 19
feat: implement createLoadTranslations factory function #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
d48da00
85d2e3c
3e644a8
db1155b
8bb1879
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import type { | ||
| I18n, | ||
| Messages, | ||
| TranslationLoader, | ||
| Translations | ||
| } from '../create-i18n/index.js' | ||
| import type { LocaleStore } from '../locale-from/index.js' | ||
|
|
||
| export interface LoadTranslations { | ||
| <Body extends Translations>(messages: Messages<Body>): Promise<Body> | ||
| } | ||
|
|
||
| /** | ||
| * Create a function to asynchronously load translations from i18n components. | ||
| * | ||
| * ```js | ||
| * import { createI18n, localeFrom, createLoadTranslations } from '@nanostores/i18n' | ||
| * | ||
| * const get = (code, components) => { | ||
| * // your fetching logic | ||
| * } | ||
| * | ||
| * export const locale = localeFrom(…) | ||
| * export const i18n = createI18n(locale, { get }) | ||
| * export const loadTranslations = createLoadTranslations(i18n, locale, get) | ||
| * ``` | ||
| * | ||
| * @param i18n Component definition function. | ||
| * @param locale Store with user’s locale. | ||
| * @param get Component loader function. | ||
| * @returns Asynchronous translations loader. | ||
| */ | ||
| export function createLoadTranslations<Locale extends string>( | ||
| i18n: I18n<Locale>, | ||
| locale: LocaleStore<Locale>, | ||
| get: TranslationLoader<Locale> | ||
| ): LoadTranslations |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| export function createLoadTranslations(i18n, locale, get) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to pass
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you are completely right here, i didn't notice that i18n exposes locale |
||
| async function loadTranslations(messages) { | ||
| let code = locale.get() | ||
|
|
||
| let translations = await get(code, [messages.component]) | ||
| if (Array.isArray(translations)) { | ||
| translations = translations.reduce((obj, item) => | ||
| Object.assign(obj, item) | ||
| ) | ||
| } | ||
|
|
||
| i18n.cache[code] = { ...i18n.cache[code], translations } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll add checks for it |
||
| return messages.get() | ||
| } | ||
|
|
||
| return loadTranslations | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import { atom } from 'nanostores' | ||
| import { deepStrictEqual, equal } from 'node:assert' | ||
| import { test } from 'node:test' | ||
|
|
||
| import { | ||
| type ComponentsJSON, | ||
| createI18n, | ||
| createLoadTranslations | ||
| } from '../index.js' | ||
|
|
||
| test('waits for translations to load', async () => { | ||
| let locale = atom<'pl'>('pl') | ||
|
ai marked this conversation as resolved.
Outdated
|
||
|
|
||
| let get = async (): Promise<ComponentsJSON> => { | ||
|
ai marked this conversation as resolved.
Outdated
|
||
| return Promise.resolve({ | ||
| component: { title: 'Tytuł' } | ||
| }) | ||
| } | ||
|
|
||
| let i18n = createI18n(locale, { get }) | ||
| let loadTranslations = createLoadTranslations(i18n, locale, get) | ||
|
|
||
| equal(i18n.loading.get(), false) | ||
|
|
||
| let messages = i18n('component', { title: 'Title' }) | ||
|
|
||
| messages.subscribe(() => {}) | ||
| equal(i18n.loading.get(), true) | ||
| deepStrictEqual(messages.get(), { title: 'Title' }) | ||
|
|
||
| deepStrictEqual(await loadTranslations(messages), { title: 'Tytuł' }) | ||
| equal(i18n.loading.get(), false) | ||
| }) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is use cases for that? SSR?
Why do we use it in React components?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's for rendering async server components which aren't updated on the client side. The translation must be available before server sends the rendered html to client.
It's different from pre-rendered client components which are later hydrated with loaded translation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://react.dev/reference/rsc/server-components
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice explanation, let’s put it to the docs.