Skip to content

Commit

Permalink
Merge pull request #10 from sveltekit-i18n/feat/raw-translations
Browse files Browse the repository at this point in the history
Added `rawTranslations`
  • Loading branch information
jarda-svoboda authored Jul 7, 2023
2 parents 22a3e56 + 6a4afb2 commit be4d1ba
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Tests
on:
workflow_dispatch:
pull_request:
types: [synchronize]
types: [opened,reopened,synchronize]
push:
branches:
- master
Expand Down
9 changes: 6 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,17 @@ You can obtain and set current locale using this writable store.
### `locales`: __Readable<string[]>__
Readable store, containing all instance locales.

### `rawTranslations`: __Readable\<{ [locale: string]: { [key: string]: string; } }> & { get: () => string; }__
Readable store, containing all loaded translations before it gets preprocessed.

### `translations`: __Readable\<{ [locale: string]: { [key: string]: string; } }> & { get: () => string; }__
Readable store, containing all loaded translations in dot-notation format.
Readable store, containing all preprocessed translations.

### `t`: __Readable<(key: string, vars?: Record<any, any>) => string> & { get: (key: string; vars?: Record<any, any>) => string; }__
This readable store returns a function you can use to obtain your (previously loaded) translations for given translation key and interpolation variables (you can use it like `$t('my.key', { variable: 'value' })` in Svelte files). You can also use `t.get` method to get the translation (e.g. `t.get('my.key', { variable: 'value' })`), which is handy in `.js` (or `.ts`) files.
This readable store returns a function you can use to obtain your (previously loaded) translations for given translation key and interpolation variables (you can use it like `$t('my.key', { variable: 'value' })` in Svelte files). You can also use `t.get` method to get the translation (e.g. `t.get('my.key', { variable: 'value' })`), which is useful in `.js` (or `.ts`) files.

### `l`: __Readable<(locale: string, key: string, vars?: Record<any, any>) => string> & { get: (locale: string, key: string, vars?: Record<any, any>) => string; }__
This readable store returns a function you can use to obtain your (previously loaded) translations for given locale, translation key and interpolation variables (you can use it like `$l('en', 'my.key', { variable: 'value' })` in Svelte files). You can also use `l.get` method to get the translation (e.g. `l.get('en', 'my.key', { variable: 'value' })`), which is handy in `.js` (or `.ts`) files.
This readable store returns a function you can use to obtain your (previously loaded) translations for given locale, translation key and interpolation variables (you can use it like `$l('en', 'my.key', { variable: 'value' })` in Svelte files). You can also use `l.get` method to get the translation (e.g. `l.get('en', 'my.key', { variable: 'value' })`), which is useful in `.js` (or `.ts`) files.

### `loadConfig`: __(config: Config) => Promise\<void>__
You can load a new `config` using this method.
Expand Down
17 changes: 16 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export default class I18n<ParserParams extends Parser.Params = any> {
get: () => get(this.isLoading),
};

private privateRawTranslations: Writable<Translations.SerializedTranslations> = writable({});

rawTranslations: ExtendedStore<Translations.SerializedTranslations> = { subscribe: this.privateRawTranslations.subscribe, get: () => get(this.rawTranslations) };

private privateTranslations: Writable<Translations.SerializedTranslations> = writable({});

translations: ExtendedStore<Translations.SerializedTranslations> = { subscribe: this.privateTranslations.subscribe, get: () => get(this.translations) };
Expand Down Expand Up @@ -235,7 +239,7 @@ export default class I18n<ParserParams extends Parser.Params = any> {
) || (
fallbackLocale && locale === sanitizedFallbackLocale && (
!translationForFallbackLocale ||
!(this.loadedKeys[sanitizedFallbackLocale] || []).includes(key)
!(this.loadedKeys[sanitizedFallbackLocale] || []).includes(key)
)),
);

Expand Down Expand Up @@ -277,6 +281,17 @@ export default class I18n<ParserParams extends Parser.Params = any> {

const translationLocales = Object.keys(translations || {});

this.privateRawTranslations.update(($rawTranslations) => translationLocales.reduce(
(acc, locale) => ({
...acc,
[locale]: {
...(acc[locale] || {}),
...translations[locale],
},
}),
$rawTranslations,
));

this.privateTranslations.update(($translations) => translationLocales.reduce(
(acc, locale) => {
let dotnotate = true;
Expand Down
4 changes: 2 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ export const sanitizeLocales = (...locales: any[]) => {
try {
const [sanitized] = Intl.Collator.supportedLocalesOf(locale);

if (!sanitized) throw new Error(`'${locale}' is non-standard.`);
if (!sanitized) throw new Error();

current = sanitized;
} catch (error) {
logger.warn(`Non-standard locale provided: '${locale}'. Check your 'translations' and 'loaders' in i18n config...`);
logger.warn(`'${locale}' locale is non-standard.`);
}

return current;
Expand Down
27 changes: 20 additions & 7 deletions tests/specs/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe('i18n instance', () => {
toHaveProperty('locale');
toHaveProperty('locales');
toHaveProperty('translations');
toHaveProperty('rawTranslations');
toHaveProperty('t');
toHaveProperty('l');
toHaveProperty('loadConfig');
Expand Down Expand Up @@ -175,15 +176,25 @@ describe('i18n instance', () => {

expect($initialized).toBe(false);
});
it('`addTranslations` method works', async () => {
it('`addTranslations` method adds raw translations', async () => {
const { addTranslations, rawTranslations } = new i18n();

const translations = getTranslations('none');

addTranslations(translations);

const $rawTranslations = rawTranslations.get();

expect($rawTranslations).toStrictEqual(translations);
});
it('`addTranslations` method adds preprocessed translations', async () => {
const { addTranslations, translations } = new i18n();

addTranslations(TRANSLATIONS);
addTranslations(getTranslations('none'));

const $translations = translations.get();

expect($translations).toEqual(
expect.objectContaining(TRANSLATIONS),
);
expect($translations).toStrictEqual(TRANSLATIONS);
});
it('`addTranslations` prevents duplicit load', async () => {
const { addTranslations, loadTranslations, loading } = new i18n({ loaders, parser, log });
Expand Down Expand Up @@ -212,12 +223,14 @@ describe('i18n instance', () => {
expect($translations[initLocale]['common.preprocess'][0].test).toBe('passed');
});
it('`preprocess` works when set to `none`', async () => {
const { loadTranslations, translations } = new i18n({ loaders, parser, log, preprocess: 'none' });
const { loadTranslations, translations, rawTranslations } = new i18n({ loaders, parser, log, preprocess: 'none' });

await loadTranslations(initLocale);

const $translations = translations.get();
const $rawTranslations = rawTranslations.get();

expect($translations).toStrictEqual($rawTranslations);
expect($translations[initLocale].common.preprocess[0].test).toBe('passed');
});
it('initializes properly with `initLocale`', async () => {
Expand Down Expand Up @@ -401,6 +414,6 @@ describe('i18n instance', () => {
await loading.toPromise();

expect(debug).toHaveBeenCalledWith('[PREFIX] Setting config.');
expect(warn).toHaveBeenCalledWith("[PREFIX] Non-standard locale provided: 'unknown'. Check your 'translations' and 'loaders' in i18n config...");
expect(warn).toHaveBeenCalledWith("[PREFIX] 'unknown' locale is non-standard.");
});
});

0 comments on commit be4d1ba

Please sign in to comment.