svelte-component-i18n 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,18 +1,74 @@
1
1
  # svelte-component-i18n
2
2
 
3
3
  A lightweight internationalization library for Svelte.
4
+
4
5
  It acts as a thin wrapper around native browser APIs, prioritizing type safety and component-level
5
6
  translation management.
6
7
 
7
- ## Usage Examples
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm i -S svelte-component-i18n
12
+ ```
13
+
14
+ ## Usage
8
15
 
9
- The following examples are simplified. Ideally you construct one `Translator` and reuse it in every
10
- component, only defining translations there.
16
+ This library consists of two parts:
17
+
18
+ 1. `Translator` keeps track of the current locale and propagates changes to all components.
19
+ 2. `Dictionary` is a component level record of translations.
20
+
21
+ First should create just one global `Translator` instance and reuse it in every component.
22
+
23
+ ```typescript
24
+ // src/lib/i18n.ts
25
+
26
+ import { Translator } from 'svelte-component-i18n';
27
+
28
+ export const translator = new Translator({
29
+ // All languages you want to support.
30
+ supportedLanguages: ['en', 'de'],
31
+ // The fallback language is the only one, where translations are required to be defined.
32
+ // If a translation for a given language is missing, the fallback language is used instead.
33
+ fallbackLanguage: 'en',
34
+ });
35
+ ```
36
+
37
+ Next you should define a `Dictionary` in your components.
38
+
39
+ ```svelte
40
+ <!--
41
+ You can define translations in a `module`-Block, as it is shared across instances of the
42
+ same component.
43
+ -->
44
+ <script lang="ts" module>
45
+ import { translator } from '$lib/i18n';
46
+
47
+ // You can destruct the dictionary into the required translation functions.
48
+ // - `translate` and `t`: Translate a key
49
+ // - `pluralize` and `p`: Translate a key taking pluralization into account
50
+ const { t } = translator.define({
51
+ myFirstTranslation: {
52
+ en: 'My first translation',
53
+ de: 'Meine erste Übersetzung',
54
+ },
55
+ });
56
+ </script>
57
+
58
+ <!--
59
+ The keys and parameters are type-checked.
60
+ If the key is not defined, the component will not compile.
61
+ -->
62
+ <p>{t('myFirstTranslation')}</p>
63
+ ```
11
64
 
12
65
  ### Language Detection
13
66
 
14
- Detecting the user's preferred language using `navigator.languages` or a previously selected language
15
- from the `localStorage`.
67
+ Detecting the user's preferred language using `navigator.languages` or a previously selected
68
+ language from the `localStorage`.
69
+
70
+ Browser globals are not defined when using server-side rendering in SvelteKit.
71
+ The provided strategies and hooks skip execution, when `navigator` or `localStorage` are missing.
16
72
 
17
73
  ```typescript
18
74
  import { fromLocalStorage, fromNavigator, toLocalStorage, Translator } from 'svelte-component-i18n';
@@ -20,25 +76,22 @@ import { fromLocalStorage, fromNavigator, toLocalStorage, Translator } from 'sve
20
76
  const localStorageKey = 'my-app-language';
21
77
 
22
78
  const translator = new Translator({
23
- supportedLanguages: ['en', 'de'],
24
- fallbackLanguage: 'en',
25
- languageStrategies: [fromLocalStorage(localStorageKey), fromNavigator()],
26
- languageHooks: [toLocalStorage(localStorageKey)],
79
+ supportedLanguages: ['en', 'de'],
80
+ fallbackLanguage: 'en',
81
+ languageStrategies: [fromLocalStorage(localStorageKey), fromNavigator()],
82
+ languageHooks: [toLocalStorage(localStorageKey)],
27
83
  });
28
84
  ```
29
85
 
30
86
  ### Language Selection
31
87
 
32
- Managing and updating the current active locale store.
88
+ The `Translator` exposes both the `currentLanguage` and the initially provided `supportedLanguages`.
89
+ You can use both to create a language selector.
90
+ The `currentLanguage` is a rune and will automatically propagate changes to all components.
33
91
 
34
92
  ```svelte
35
- <script lang="ts">
36
- import { Translator } from 'svelte-component-i18n';
37
-
38
- const translator = new Translator({
39
- supportedLanguages: ['en', 'de'],
40
- fallbackLanguage: 'en',
41
- });
93
+ <script lang="ts" module>
94
+ import { translator } from '$lib/i18n';
42
95
  </script>
43
96
 
44
97
  <select bind:value={translator.currentLanguage}>
@@ -53,15 +106,15 @@ Managing and updating the current active locale store.
53
106
  Basic key-value mapping for static text.
54
107
 
55
108
  ```svelte
56
- <script lang="ts">
57
- import { translator } from '$lib/my-globally-defined-translator';
109
+ <script lang="ts" module>
110
+ import { translator } from '$lib/i18n';
58
111
 
59
- const { t } = translator.define({
112
+ const { t } = translator.define({
60
113
  simple: {
61
- en: 'Simple',
62
- de: 'Einfach',
114
+ en: 'Simple',
115
+ de: 'Einfach',
63
116
  },
64
- });
117
+ });
65
118
  </script>
66
119
 
67
120
  {t('simple')}
@@ -69,24 +122,24 @@ const { t } = translator.define({
69
122
 
70
123
  ### Pluralization
71
124
 
72
- Using `Intl.PluralRules` logic to handle count-based text variations.
125
+ Using `Intl.PluralRules`[^1] logic to handle count-based text variations.
73
126
 
74
127
  ```svelte
75
- <script lang="ts">
76
- import { translator } from '$lib/my-globally-defined-translator';
128
+ <script lang="ts" module>
129
+ import { translator } from '$lib/i18n';
77
130
 
78
- const { p } = translator.define({
131
+ const { p } = translator.define({
79
132
  pluralized: {
80
- en: {
81
- one: 'One thing',
82
- other: 'Many things',
83
- },
84
- de: {
85
- one: 'Ein Ding',
86
- other: 'Viele Dinge',
87
- },
133
+ en: {
134
+ one: 'One thing',
135
+ other: 'Many things',
136
+ },
137
+ de: {
138
+ one: 'Ein Ding',
139
+ other: 'Viele Dinge',
140
+ },
88
141
  },
89
- });
142
+ });
90
143
  </script>
91
144
 
92
145
  {p('pluralized', 1)}
@@ -99,15 +152,15 @@ Instead of defining static structures you can also define functions, which retur
99
152
  Template literals can be used to interpolate text.
100
153
 
101
154
  ```svelte
102
- <script lang="ts">
103
- import { translator } from '$lib/my-globally-defined-translator';
155
+ <script lang="ts" module>
156
+ import { translator } from '$lib/i18n';
104
157
 
105
- const { t } = translator.define({
158
+ const { t } = translator.define({
106
159
  parameterized: (name: string) => ({
107
- en: `Hello ${name}`,
108
- de: `Hallo ${name}`,
160
+ en: `Hello ${name}`,
161
+ de: `Hallo ${name}`,
109
162
  }),
110
- });
163
+ });
111
164
  </script>
112
165
 
113
166
  {t('parameterized', 'Svelte')}
package/dist/detect.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type LanguageStrategy<Languages extends string> = (supportedLanguages: Languages[]) => Languages | undefined;
2
- export declare function fromNavigator<Languages extends string>(): LanguageStrategy<Languages>;
3
- export declare function fromLocalStorage<Languages extends string>(key: string): LanguageStrategy<Languages>;
2
+ export declare function fromNavigator<Languages extends string>(navigator?: typeof globalThis.navigator): LanguageStrategy<Languages>;
3
+ export declare function fromLocalStorage<Languages extends string>(key: string, localStorage?: Storage): LanguageStrategy<Languages>;
4
4
  export type LanguageHook<Languages extends string> = (language: Languages) => unknown;
5
- export declare function toLocalStorage<Languages extends string>(key: string): LanguageHook<Languages>;
5
+ export declare function toLocalStorage<Languages extends string>(key: string, localStorage?: Storage): LanguageHook<Languages>;
package/dist/detect.js CHANGED
@@ -1,7 +1,6 @@
1
- import { browser } from '$app/environment';
2
- export function fromNavigator() {
1
+ export function fromNavigator(navigator = globalThis.navigator) {
3
2
  return (supportedLanguages) => {
4
- if (!browser) {
3
+ if (!navigator) {
5
4
  return;
6
5
  }
7
6
  for (const navigatorLanguage of navigator.languages) {
@@ -12,9 +11,9 @@ export function fromNavigator() {
12
11
  }
13
12
  };
14
13
  }
15
- export function fromLocalStorage(key) {
14
+ export function fromLocalStorage(key, localStorage = globalThis.localStorage) {
16
15
  return (supportedLanguages) => {
17
- if (!browser) {
16
+ if (!localStorage) {
18
17
  return;
19
18
  }
20
19
  const localStorageLanguage = localStorage.getItem(key);
@@ -27,9 +26,9 @@ export function fromLocalStorage(key) {
27
26
  }
28
27
  };
29
28
  }
30
- export function toLocalStorage(key) {
29
+ export function toLocalStorage(key, localStorage = globalThis.localStorage) {
31
30
  return (language) => {
32
- if (!browser) {
31
+ if (!localStorage) {
33
32
  return;
34
33
  }
35
34
  localStorage.setItem(key, language);
package/package.json CHANGED
@@ -1,6 +1,16 @@
1
1
  {
2
2
  "name": "svelte-component-i18n",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
+ "license": "BSD-3-Clause",
5
+ "description": "Lightweight internationalization library for Svelte.",
6
+ "author": "Lukas Dietrich <lukas@lukasdietrich.com>",
7
+ "repository": "github:lukasdietrich/svelte-component-i18n",
8
+ "keywords": [
9
+ "svelte",
10
+ "i18n",
11
+ "internationalization",
12
+ "translation"
13
+ ],
4
14
  "scripts": {
5
15
  "dev": "vite dev",
6
16
  "build": "vite build && npm run prepack",
@@ -55,8 +65,5 @@
55
65
  "typescript-eslint": "^8.48.1",
56
66
  "vite": "^7.2.6",
57
67
  "vitest": "^4.0.15"
58
- },
59
- "keywords": [
60
- "svelte"
61
- ]
68
+ }
62
69
  }