Skip to content

Commit

Permalink
exports fix
Browse files Browse the repository at this point in the history
  • Loading branch information
eddow committed May 1, 2024
1 parent 00dba98 commit e9de0bb
Show file tree
Hide file tree
Showing 10 changed files with 49 additions and 26 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ In case of PoC, only the root zone can be used.
It heavily relies on the [hard-coded Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) mechanism, especially for date/number formats as well as plural and ordinal formations.

Examples:

```
Hello {=1|here}
There {plural|$1|is|are} {number|$1} {plural|$1|entry|entries}
Expand All @@ -128,6 +129,7 @@ There {plural|$1|is|are} {number|$1} {plural|$1|entry|entries}
## Error reporting

[Error reporting](./docs/client.md#reports) can be done either with a global value as such: ([details](./docs/client.md#global-reporting))

```ts
import { reports, type TContext } from "omni18n";

Expand All @@ -136,11 +138,12 @@ reports.error = (context: TContext, error: string, spec: object) => string
```

Or the [object-oriented way](./docs/client.md#oo-reporting) by extending `I18nClient` implementing the `ReportingClient` interface.

```ts
missing(key: string, fallback: OmnI18n.Translation | undefined, zones: OmnI18n.Zone[]): string
error(key: string, error: string, spec: object, zones: OmnI18n.Zone[]): string
```

## TODO

- testing the errors - both in interpolation and deserialization
- testing the errors - both in interpolation and deserialization
13 changes: 7 additions & 6 deletions docs/db.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ A kind of API has been designed for the server to be able to _modify_ the conten

Here, we get already in the realm where we can specify `KeyInfos` and `TextInfos`. The former is given by developers, in english or some common language if text is needed - and appear in the `keys` database - and the `TextInfo`, more often used/edited by the translators and appearing in the `translations` database.

If a database implementation is meant to be generic, it should store the `...Infos` as json I guess or something, but an application can specify both these generic arguments *and* the database adapter to deal with it.
If a database implementation is meant to be generic, it should store the `...Infos` as json I guess or something, but an application can specify both these generic arguments _and_ the database adapter to deal with it.

The `KeyInfo` might store information like notes from the dev, a flag to know if the text is pure, html, md, ... Whatever concerns development.

The `Textinfo` might store translation notes I guess, a link to a discussion with chatGPT, I really don't know - in case of doubt, let the default `{}`


```ts
...Infos extends {} = {}
```
Expand Down Expand Up @@ -80,6 +79,7 @@ The first one retrieves the list of translations for a key, the second the key's
### Setters
#### Translate
> Write in the texts table, read in the keys table
```ts
Expand Down Expand Up @@ -117,12 +117,13 @@ reKey(key: string, newKey?: string): Promise<{ zone: string; locales: Locale[] }
FileDB is basically a MemDB with a file I/O ability. It is constructed with a file name and a `delay`, specifying the defer time between modifications and file writing (if a modification intervenes before file writing, the writing is deferred again to group it)
This allows:
- All the translations to simply be gathered under a file under source control (backup-able)
- The development activities (adding/removing/removing/rezoning a key) to be made and applied on commit/merge, and the "translation" (text-change) activities to still be available through the UI in real time
#### File format
The serialization file-format is specific for regexp-ability *and* human interactions; grouping is done by indentation (made with tabulations - `\t`).
The serialization file-format is specific for regexp-ability _and_ human interactions; grouping is done by indentation (made with tabulations - `\t`).
`KeyInfos` and `TextInfos` are stored in [`hjson`](https://www.npmjs.com/package/hjson) format
Expand All @@ -133,6 +134,7 @@ A line beginning with no tabs is a key specification
```
[text-key]:[zone]
```
```
[text-key][{ SomeKeyInfos: 'hjson format' }]:[zone]
```
Expand All @@ -143,17 +145,17 @@ A line beginning with no tabs is a key specification
A line beginning with one tab is a locale specification for the key "en cours"
```
[locale]:
```
```
[locale][{ SomeTextInfos: 'hjson format' }]:
```
##### 2-tabs
A line beginning with two tabs is the *continuation* of the translation.
A line beginning with two tabs is the _continuation_ of the translation.
```
[locale]:Line1
Expand All @@ -165,4 +167,3 @@ Will specify `locale: "Line1\nLine2"`
##### 3-tabs
A line beginning with three tabs is the continuation of a translation containing a tab ... &c.
2 changes: 1 addition & 1 deletion docs/interpolation.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,4 @@ The keywords (`one`, `other`, ...) come from [`Intl.PluralRules`](https://develo
- `plural(n, spec)`:
- If `spec` is a word, the `internals.plurals` rule is used (`{plural|1|cat}`-> "cat", `{plural|2|cat}`-> "cats").
- The specification can use the `Intl.PluralRules` (ex: `{plural|$1|one:ox,other:oxen}`)
- A specific case is made for languages who use `one/other` (like english) : `{plural|$1|ox|oxen}`
- A specific case is made for languages who use `one/other` (like english) : `{plural|$1|ox|oxen}`
19 changes: 12 additions & 7 deletions docs/server.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Server

The server class *shouldn't* have to be extended (now, you do what you want)
The server class _shouldn't_ have to be extended (now, you do what you want)

It is **not** instantiated client-side and is instantiated once/per request/per user on the server-side.

## Standard server

The usual use-case is to have a server instance created with a [`DB`](./db.md#structure) instance who provide a `condense` member.

```ts
type Condense = (locales: Locale[], zones: Zone[]) => Promise<CondensedDictionary[]>
```
Expand All @@ -25,10 +26,10 @@ On the client-side, shall it be UI/REST-api, communication with a worker, websoc
```ts
const condense: Condense = async (locales: Locale[], zones: Zone[]) => {
const {locales: urlLocales, zones: urlZones} = Server.specs2url(locales, zones)
const { locales: urlLocales, zones: urlZones } = Server.specs2url(locales, zones)
const result = await fetch(`/condense?locales=${urlLocales}&zones=${urlZones}`)
// if result.status is ok & stuff
return <CondensedDictionary>(await result.json())
return <CondensedDictionary>await result.json()
}
```

Expand All @@ -52,18 +53,21 @@ Imagine that you wish your application to shine so much that you want the transl

Yes, that's how nerdy this `InteractiveServer` is - use only if you wish to.

1- An instance has to be created per *client tab* - or if you wish, make a service worker (but make a PR about it if you do)
1- An instance has to be created per _client tab_ - or if you wish, make a service worker (but make a PR about it if you do)
2- Instances have to be `.destroy()`-ed when the channel is closed

Interactive servers are created with a second parameter:

```ts
(entries: Record<string, [string, string] | undefined>)=> Promise<void>
;(entries: Record<string, [string, string] | undefined>) => Promise<void>
```

And, you guessed it, this one should just be forwarded to `OmnI18nClient::modified` through whichever medium you wish/can (I guess a websocket or such)

### Exposed interface

#### `InteractiveDB` forwards.

> To be called by the client
```ts
Expand All @@ -83,9 +87,10 @@ key(
): Promise<void>
```

Only the `key` function differs as it takes the *translation modifications* as an argument (to *remove* a translation, specify `locale: undefined`)
Only the `key` function differs as it takes the _translation modifications_ as an argument (to _remove_ a translation, specify `locale: undefined`)

#### DB notifications

> To be called by the DB
If a DB is reloaded or modified from another source and manage to have the event, one can raise the flag with:
Expand All @@ -99,4 +104,4 @@ modifiedText(key: TextKey, locale: Locale, text?: Translation): Promise<void>

When all the modifications are done, the `propagate()` method can be called: it will propagate the events to all other `InteractiveServer` instances registered in the same `subscriptions` global variable (not accessible, just managed internally)

All the servers who are concerned by the modifications will use their `modified` call-back
All the servers who are concerned by the modifications will use their `modified` call-back
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "omni18n",
"version": "1.0.5",
"version": "1.0.6",
"description": "",
"main": "dist/index.js",
"module": "dist/index.js",
Expand Down
2 changes: 0 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import typescript from 'rollup-plugin-typescript2'
import json from '@rollup/plugin-json'
import terser from '@rollup/plugin-terser'

export default {
input: './src/index.ts',
Expand All @@ -20,7 +19,6 @@ export default {
exclude: ['./node_modules']
}
}),
terser(),
json()
]
}
7 changes: 5 additions & 2 deletions src/client/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
Translatable,
ReportingClient
} from './types'
import { interpolate } from './interpolation'

function entry(t: OmnI18n.Translation, z: OmnI18n.Zone, isFallback?: boolean): ClientDictionary {
return { [text]: t, [zone]: z, ...(isFallback ? { [fallback]: true } : {}) }
Expand Down Expand Up @@ -214,7 +213,11 @@ export function bulkDictionary<T extends Translatable = Translatable>(
const rv: any = {}
const subCtx = { ...context, key }
const value = () =>
interpolate(subCtx, obj[fallback] ? reportMissing(subCtx, obj[text]) : obj[text]!, args)
context.client.interpolate(
subCtx,
obj[fallback] ? reportMissing(subCtx, obj[text]) : obj[text]!,
args
)
if (Object.keys(obj).every((k) => typeof k === 'symbol')) return value()
for (const [k, v] of Object.entries(obj))
rv[k] = dictionaryToTranslation(v, key ? `${key}.${k}` : k)
Expand Down
2 changes: 1 addition & 1 deletion src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export {
type Translator,
type ReportingClient
} from './types'
export { reports, bulkObject, bulkDictionary as objectFromDictionary } from './helpers'
export { reports, bulkObject, bulkDictionary } from './helpers'
export { formats, processors } from './interpolation'
19 changes: 16 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
export * from './client/index'
export * from './server/index'
export * from './db/index'
export {
I18nClient,
type TContext,
getContext,
TranslationError,
type ClientDictionary,
type Translator,
type ReportingClient,
reports,
bulkObject,
bulkDictionary,
formats,
processors
} from './client/index'
export { I18nServer, InteractiveServer, type Modification } from './server/index'
export { FileDB, MemDB, type MemDBDictionary, type MemDBDictionaryEntry } from './db/index'

declare global {
interface Set<T> {
Expand Down
4 changes: 2 additions & 2 deletions test/specifics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
TContext,
Translator,
bulkObject,
objectFromDictionary,
bulkDictionary,
reports
} from '../src/index'
import { readFile, writeFile, unlink } from 'node:fs/promises'
Expand Down Expand Up @@ -58,7 +58,7 @@ describe('bulk', () => {

test('from dictionary', async () => {
misses.mockClear()
const built = objectFromDictionary(T.struct, { parm: 42 })
const built = bulkDictionary(T.struct, { parm: 42 })
expect(built).toEqual(expected)
expect(misses).toHaveBeenCalledWith('struct.missing')
expect('' + built.sub).toBe('toString')
Expand Down

0 comments on commit e9de0bb

Please sign in to comment.