Skip to content

Commit

Permalink
Merge pull request #15 from robisim74/extract
Browse files Browse the repository at this point in the history
Feat: extraction of translations
  • Loading branch information
robisim74 committed Nov 12, 2022
2 parents ba91656 + f50f80d commit da78cb8
Show file tree
Hide file tree
Showing 38 changed files with 1,055 additions and 519 deletions.
136 changes: 74 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,7 @@
Live example on [StackBlitz](https://stackblitz.com/edit/qwik-speak)

## Speak context
```mermaid
stateDiagram-v2
State1: SpeakState
State2: SpeakLocale
State3: Translation
State4: SpeakConfig
State5: TranslateFn
State1 --> State2
State1 --> State3
State1 --> State4
State1 --> State5
note right of State2
- lang
- extension (Intl)
- currency
- timezone
- unit
end note
note right of State3
key-value pairs
of translation data
end note
note right of State4: Configuration
note right of State5
Custom APIs:
- loadTranslation$
- resolveLocale$
- storeLocale$
- handleMissingTranslation$
end note
```

## Usage
### Getting started
```shell
npm install qwik-speak --save-dev
```
Expand All @@ -50,8 +16,9 @@ import { $translate as t, plural as p } from 'qwik-speak';
export default component$(() => {
return (
<>
<p>{t('app.title', { name: 'Qwik Speak' })}</p> {/* I'm Qwik Speak */}
<p>{p(1, 'app.devs')}</p> {/* 1 software developer */}
<h1>{t('app.title')}</h1> {/* Qwik Speak */}
<p>{t('home.greeting', { name: 'Qwik Speak' })}</p> {/* Hi! I am Qwik Speak */}
<p>{p(state.count, 'runtime.devs')}</p> {/* 1 software developer, 2 software developers */}
</>
);
});
Expand All @@ -64,7 +31,7 @@ export default component$(() => {
return (
<>
<p>{fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' })}</p> {/* Wednesday, July 20, 2022 at 7:09 AM */}
<p>{rt(-1, 'day')}</p> {/* 1 day ago */}
<p>{rt(-1, 'second')}</p> {/* 1 second ago */}
<p>{fn(1000000, { style: 'currency' })}</p> {/* $1,000,000.00 */}
</>
);
Expand All @@ -85,19 +52,16 @@ export const config: SpeakConfig = {
]
};
```
Assets will be loaded through the implementation of `loadTranslation$` function below. You can load _json_ files or call an _endpoint_ to return a `Translation` object for each language:
Assets will be loaded through the implementation of `loadTranslation$` function below. You can load _json_ files or call an _endpoint_ to return a `Translation` object of key-value pairs for each language:

```json
{
"app": {
"title": "I'm {{name}}",
"devs": {
"one": "{{value}} software developer",
"other": "{{value}} software developers"
}
"title": "Qwik Speak"
}
}
```
### Custom APIs
#### Custom APIs
```typescript
import { $ } from '@builder.io/qwik';

Expand Down Expand Up @@ -153,15 +117,27 @@ export default component$(() => {
);
});
```
### Lazy loading of translation data
### Scoped translations
```mermaid
C4Container
Container_Boundary(a, "App") {
Component(a0, "QwikSpeak", "", "Uses Speak context")
Container_Boundary(b1, "Home") {
Component(a10, "Speak", "", "Adds its own translation data to the context")
}
Container_Boundary(b2, "Page") {
Component(a20, "Speak", "", "Adds its own translation data to the context")
}
}
```
Create a different translation data file (asset) for each page and use `Speak` component to add translation data to the context:
```jsx
import { Speak } from 'qwik-speak';

export default component$(() => {
return (
/**
* Add Home translation (only available in child components)
* Add Home translations (only available in child components)
*/
<Speak assets={['home']}>
<Home />
Expand All @@ -183,17 +159,7 @@ export default component$(() => {
```
The translation data of the additional languages are preloaded along with the current language. They can be used as a fallback for missing values by implementing `handleMissingTranslation$`, or for multilingual pages.

## Production
You have three solutions:
- **Build as is** Translation happens _at runtime_: translations are loaded during SSR or on client, and the lookup also happens at runtime as in development mode
- **Build using Qwik Speak Inline Vite plugin** Translation happens _at compile-time_: translations are loaded and inlined during the buid (both in server file and in chunks sent to the browser)
- **Build using Qwik Speak Inline Vite plugin & runtime** Translation happens _at compile-time_ or _at runtime_ as needed: static translations are loaded and inlined during the buid, while dynamic translations occur at runtime

See [Qwik Speak Inline Vite plugin](./tools/inline.md) for more information on how it works and how to use it.

### Static Site Generation (SSG)
Using SSG offered by Qwik City, you can prerender the pages for each language.

### Localized routing
What you need:
- A `lang` parameter in the root, like:
```
Expand All @@ -206,9 +172,21 @@ What you need:
index.html
```
- Handle the localized routing in `resolveLocale$` and `storeLocale$`
- Qwik City Static Site Generation config and dynamic routes

The [sample app](./src/app) in this project uses _Qwik Speak Inline Vite plugin & runtime_ solution and implements SSG.
## Extraction of translations
To extract translations directly from the components, a command is available that automatically generates the files with the keys and default values.

See [Qwik Speak Extract](./tools/extract.md) for more information on how to use it.

## Production
You have three solutions:
- **Build as is** Translation happens _at runtime_: translations are loaded during SSR or on client, and the lookup also happens at runtime as in development mode
- **Build using Qwik Speak Inline Vite plugin** Translation happens _at compile-time_: translations are loaded and inlined during the build (both in server file and in chunks sent to the browser)
- **Build using Qwik Speak Inline Vite plugin & runtime** Translation happens _at compile-time_ or _at runtime_ as needed: static translations are loaded and inlined during the build, while dynamic translations occur at runtime

See [Qwik Speak Inline Vite plugin](./tools/inline.md) for more information on how it works and how to use it.

The [sample app](./src/app) in this project uses a localized routing, _Qwik Speak Inline Vite plugin & runtime_ solution and implements SSG.

## Speak config
- `defaultLocale`
Expand All @@ -226,7 +204,7 @@ Separator of nested keys. Default is `.`
- `keyValueSeparator`
Key-value separator. Default is `@@`

The default value of a key can be passed directly into the string: `t("app.title@@I'm {{name}}")`
The default value of a key can be passed directly into the string: `t('app.title@@Qwik Speak')`

The `SpeakLocale` object contains the `lang`, in the format `language[-script][-region]`, where:
- `language`: ISO 639 two-letter or three-letter code
Expand Down Expand Up @@ -258,9 +236,42 @@ Formats a number

- `changeLocale(newLocale: SpeakLocale, ctx: SpeakState)`
Changes locale at runtime: loads translation data and rerenders components that uses translations

### Speak context
```mermaid
stateDiagram-v2
State1: SpeakState
State2: SpeakLocale
State3: Translation
State4: SpeakConfig
State5: TranslateFn
State1 --> State2
State1 --> State3
State1 --> State4
State1 --> State5
note right of State2
- lang
- extension (Intl)
- currency
- timezone
- unit
end note
note right of State3
key-value pairs
of translation data
end note
note right of State4: Configuration
note right of State5
Custom APIs:
- loadTranslation$
- resolveLocale$
- storeLocale$
- handleMissingTranslation$
end note
```

- `useSpeakContext()`
Returns the Speak context
Returns the Speak state

- `useSpeakLocale()`
Returns the locale in Speak context
Expand Down Expand Up @@ -305,8 +316,9 @@ npm run serve.ssg
```

## What's new
> Released v0.1.0
> Released v0.2.0
- Extract translations: [Qwik Speak Extract](./tools/extract.md)
- Inline translation data at compile time: [Qwik Speak Inline Vite plugin](./tools/inline.md)

## License
Expand Down
3 changes: 0 additions & 3 deletions adaptors/express/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ export default extendConfig(baseConfig, () => {
},
},
plugins: [
expressAdaptor({
staticGenerate: true,
}),
],
};
});
6 changes: 6 additions & 0 deletions banner.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @license
* Qwik Speak
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/robisim74/qwik-speak/blob/main/LICENSE
*/
Loading

0 comments on commit da78cb8

Please sign in to comment.