@translation-cms/sync 1.1.59 → 1.1.61

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,3 +1,23 @@
1
+ # React TranslationProvider
2
+
3
+ Wrap je app of componenten met de TranslationProvider om i18n context te
4
+ leveren:
5
+
6
+ ```tsx
7
+ import { TranslationProvider } from '@translation-cms/sync';
8
+
9
+ export default function RootLayout({
10
+ children,
11
+ }: {
12
+ children: React.ReactNode;
13
+ }) {
14
+ return <TranslationProvider locale="nl">{children}</TranslationProvider>;
15
+ }
16
+ ```
17
+
18
+ De provider initialiseert i18n en zorgt dat de context beschikbaar is voor alle
19
+ onderliggende componenten.
20
+
1
21
  # @translation-cms/sync
2
22
 
3
23
  Automatically scan translation keys in your codebase and sync them to the
@@ -39,7 +59,10 @@ root. Values here are merged with env vars — CLI args take highest priority.
39
59
  "reservedCssNamespaces": ["after", "before"],
40
60
  "previewRoutes": {
41
61
  "namespace:key": [
42
- { "route": "/[locale]/blog/[slug]", "params": { "slug": "first-post" } }
62
+ {
63
+ "route": "/[locale]/blog/[slug]",
64
+ "params": { "slug": "first-post" }
65
+ }
43
66
  ]
44
67
  }
45
68
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { TranslationProvider, type TranslationProviderProps, } from './translation-provider.js';
1
2
  export { CMSClient, getCMSClient, type CMSConfig, type TranslationResponse, type NamespacedTranslations, } from './client.js';
2
3
  export { initPreviewListener, cleanupPreviewListener, type PreviewListenerOptions, } from './preview-listener.js';
3
4
  export { type TranslationsConfig } from './config.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACH,SAAS,EACT,YAAY,EACZ,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,GAC9B,MAAM,aAAa,CAAC;AAGrB,OAAO,EACH,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,sBAAsB,GAC9B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGtD,OAAO,EACH,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,GACnB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACH,mBAAmB,EACnB,KAAK,wBAAwB,GAChC,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACH,SAAS,EACT,YAAY,EACZ,KAAK,SAAS,EACd,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,GAC9B,MAAM,aAAa,CAAC;AAGrB,OAAO,EACH,mBAAmB,EACnB,sBAAsB,EACtB,KAAK,sBAAsB,GAC9B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGtD,OAAO,EACH,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,GACnB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ // TranslationProvider (React context for i18n)
2
+ export { TranslationProvider, } from './translation-provider.js';
1
3
  // CMS client (browser-safe)
2
4
  export { CMSClient, getCMSClient, } from './client.js';
3
5
  // Preview listener (browser-safe)
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,OAAO,EACH,SAAS,EACT,YAAY,GAIf,MAAM,aAAa,CAAC;AAErB,kCAAkC;AAClC,OAAO,EACH,mBAAmB,EACnB,sBAAsB,GAEzB,MAAM,uBAAuB,CAAC;AAK/B,6CAA6C;AAC7C,OAAO,EACH,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,SAAS,GAIZ,MAAM,cAAc,CAAC;AAEtB,oDAAoD;AACpD,OAAO,EAAE,UAAU,EAA0B,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,OAAO,EACH,mBAAmB,GAEtB,MAAM,2BAA2B,CAAC;AACnC,4BAA4B;AAC5B,OAAO,EACH,SAAS,EACT,YAAY,GAIf,MAAM,aAAa,CAAC;AAErB,kCAAkC;AAClC,OAAO,EACH,mBAAmB,EACnB,sBAAsB,GAEzB,MAAM,uBAAuB,CAAC;AAK/B,6CAA6C;AAC7C,OAAO,EACH,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,SAAS,GAIZ,MAAM,cAAc,CAAC;AAEtB,oDAAoD;AACpD,OAAO,EAAE,UAAU,EAA0B,MAAM,WAAW,CAAC"}
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { getCMSClient } from './client.js';
3
+ import type { TOptions, TranslationResponse } from './client.js';
4
+ export interface TranslationProviderProps {
5
+ children: React.ReactNode;
6
+ locale: string;
7
+ namespaces?: string[];
8
+ /**
9
+ * Optionally override CMS config (for multi-project setups)
10
+ */
11
+ config?: Parameters<typeof getCMSClient>[0];
12
+ }
13
+ interface TranslationContextValue {
14
+ t: (key: string, options?: TOptions) => string;
15
+ tDynamic: (key: string, options?: TOptions) => string;
16
+ isLoading: boolean;
17
+ locale: string;
18
+ translations: TranslationResponse;
19
+ }
20
+ export declare function TranslationProvider({ children, locale, namespaces, config, }: TranslationProviderProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function useTranslationContext(): TranslationContextValue;
22
+ export {};
23
+ //# sourceMappingURL=translation-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation-provider.d.ts","sourceRoot":"","sources":["../src/translation-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAMN,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/C;AAGD,UAAU,uBAAuB;IAC7B,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAC;IAC/C,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,KAAK,MAAM,CAAC;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,mBAAmB,CAAC;CACrC;AAMD,wBAAgB,mBAAmB,CAAC,EAChC,QAAQ,EACR,MAAM,EACN,UAAuB,EACvB,MAAM,GACT,EAAE,wBAAwB,2CA6G1B;AAGD,wBAAgB,qBAAqB,4BAOpC"}
@@ -0,0 +1,95 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useState, useMemo, } from 'react';
3
+ import { getCMSClient } from './client.js';
4
+ const TranslationContext = createContext(undefined);
5
+ export function TranslationProvider({ children, locale, namespaces = ['common'], config, }) {
6
+ // Compose a key from dependencies to reset loading state
7
+ const depsKey = useMemo(() => [locale, JSON.stringify(namespaces), JSON.stringify(config)].join('|'), [locale, namespaces, config]);
8
+ const [state, setState] = useState(() => ({
9
+ isLoading: true,
10
+ translations: {},
11
+ depsKey,
12
+ }));
13
+ // Reset loading state when depsKey changes
14
+ useEffect(() => {
15
+ if (state.depsKey !== depsKey) {
16
+ setState({ isLoading: true, translations: {}, depsKey });
17
+ }
18
+ // eslint-disable-next-line react-hooks/exhaustive-deps
19
+ }, [depsKey]);
20
+ useEffect(() => {
21
+ if (state.depsKey !== depsKey)
22
+ return;
23
+ let cancelled = false;
24
+ const client = getCMSClient(config);
25
+ client
26
+ .getTranslations(namespaces, locale)
27
+ .then((data) => {
28
+ if (!cancelled) {
29
+ setState({ isLoading: false, translations: data, depsKey });
30
+ }
31
+ });
32
+ return () => {
33
+ cancelled = true;
34
+ };
35
+ }, [depsKey, config, namespaces, locale, state.depsKey]);
36
+ // Plural/variable interpolation logic (mirrors use-translation.ts)
37
+ const resolveTranslation = useMemo(() => {
38
+ return (key, options) => {
39
+ // Plural key selection: try count-specific suffix first
40
+ let resolvedKey = key;
41
+ if (options && typeof options.count === 'number') {
42
+ const count = options.count;
43
+ const suffix = count === 0 ? '_zero' : count === 1 ? '_one' : '_other';
44
+ const pluralKey = `${key}${suffix}`;
45
+ if (pluralKey in state.translations) {
46
+ resolvedKey = pluralKey;
47
+ }
48
+ else if (`${key}_other` in state.translations) {
49
+ resolvedKey = `${key}_other`;
50
+ }
51
+ }
52
+ let value;
53
+ if (resolvedKey in state.translations) {
54
+ value = state.translations[resolvedKey];
55
+ }
56
+ else if (key in state.translations) {
57
+ value = state.translations[key];
58
+ }
59
+ else {
60
+ value = options?.defaultValue ?? key;
61
+ }
62
+ // Interpolate {{variable}} placeholders (i18next default format)
63
+ if (options) {
64
+ value = value.replace(/\{\{(\w+)\}\}/g, (_, varKey) => varKey in options
65
+ ? String(options[varKey])
66
+ : `{{${varKey}}}`);
67
+ }
68
+ return value;
69
+ };
70
+ }, [state.translations]);
71
+ const t = useMemo(() => (key, options) => resolveTranslation(key, options), [resolveTranslation]);
72
+ const tDynamic = t; // identical for now
73
+ const contextValue = useMemo(() => ({
74
+ t,
75
+ tDynamic,
76
+ isLoading: state.isLoading,
77
+ locale,
78
+ translations: state.translations,
79
+ }), [t, tDynamic, state.isLoading, locale, state.translations]);
80
+ // Set <html lang="..."> for accessibility
81
+ useEffect(() => {
82
+ if (typeof document !== 'undefined') {
83
+ document.documentElement.lang = locale;
84
+ }
85
+ }, [locale]);
86
+ return (_jsx(TranslationContext.Provider, { value: contextValue, children: children }));
87
+ }
88
+ // Consumer hook
89
+ export function useTranslationContext() {
90
+ const ctx = useContext(TranslationContext);
91
+ if (!ctx)
92
+ throw new Error('useTranslationContext must be used within a TranslationProvider');
93
+ return ctx;
94
+ }
95
+ //# sourceMappingURL=translation-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation-provider.js","sourceRoot":"","sources":["../src/translation-provider.tsx"],"names":[],"mappings":";AAAA,OAAc,EACV,aAAa,EACb,UAAU,EACV,SAAS,EACT,QAAQ,EACR,OAAO,GACV,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAsB3C,MAAM,kBAAkB,GAAG,aAAa,CACpC,SAAS,CACZ,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,EAChC,QAAQ,EACR,MAAM,EACN,UAAU,GAAG,CAAC,QAAQ,CAAC,EACvB,MAAM,GACiB;IACvB,yDAAyD;IACzD,MAAM,OAAO,GAAG,OAAO,CACnB,GAAG,EAAE,CACD,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAC7D,GAAG,CACN,EACL,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAC/B,CAAC;IACF,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAI/B,GAAG,EAAE,CAAC,CAAC;QACN,SAAS,EAAE,IAAI;QACf,YAAY,EAAE,EAAE;QAChB,OAAO;KACV,CAAC,CAAC,CAAC;IAEJ,2CAA2C;IAC3C,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAC5B,QAAQ,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,uDAAuD;IAC3D,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,KAAK,CAAC,OAAO,KAAK,OAAO;YAAE,OAAO;QACtC,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM;aACD,eAAe,CAAC,UAAU,EAAE,MAAM,CAAC;aACnC,IAAI,CAAC,CAAC,IAAyB,EAAE,EAAE;YAChC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACb,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;YAChE,CAAC;QACL,CAAC,CAAC,CAAC;QACP,OAAO,GAAG,EAAE;YACR,SAAS,GAAG,IAAI,CAAC;QACrB,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzD,mEAAmE;IACnE,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,EAAE;QACpC,OAAO,CAAC,GAAW,EAAE,OAAkB,EAAU,EAAE;YAC/C,wDAAwD;YACxD,IAAI,WAAW,GAAG,GAAG,CAAC;YACtB,IAAI,OAAO,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;gBAC5B,MAAM,MAAM,GACR,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;gBAC5D,MAAM,SAAS,GAAG,GAAG,GAAG,GAAG,MAAM,EAAE,CAAC;gBACpC,IAAI,SAAS,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;oBAClC,WAAW,GAAG,SAAS,CAAC;gBAC5B,CAAC;qBAAM,IAAI,GAAG,GAAG,QAAQ,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;oBAC9C,WAAW,GAAG,GAAG,GAAG,QAAQ,CAAC;gBACjC,CAAC;YACL,CAAC;YACD,IAAI,KAAa,CAAC;YAClB,IAAI,WAAW,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;gBACpC,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,CAAW,CAAC;YACtD,CAAC;iBAAM,IAAI,GAAG,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;gBACnC,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,GAAG,CAAW,CAAC;YAC9C,CAAC;iBAAM,CAAC;gBACJ,KAAK,GAAI,OAAO,EAAE,YAAmC,IAAI,GAAG,CAAC;YACjE,CAAC;YACD,iEAAiE;YACjE,IAAI,OAAO,EAAE,CAAC;gBACV,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAClD,MAAM,IAAI,OAAO;oBACb,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACzB,CAAC,CAAC,KAAK,MAAM,IAAI,CACxB,CAAC;YACN,CAAC;YACD,OAAO,KAAK,CAAC;QACjB,CAAC,CAAC;IACN,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC;IAEzB,MAAM,CAAC,GAAG,OAAO,CACb,GAAG,EAAE,CAAC,CAAC,GAAW,EAAE,OAAkB,EAAE,EAAE,CACtC,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,EACpC,CAAC,kBAAkB,CAAC,CACvB,CAAC;IACF,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,oBAAoB;IAExC,MAAM,YAAY,GAAG,OAAO,CACxB,GAAG,EAAE,CAAC,CAAC;QACH,CAAC;QACD,QAAQ;QACR,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM;QACN,YAAY,EAAE,KAAK,CAAC,YAAY;KACnC,CAAC,EACF,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,YAAY,CAAC,CAC7D,CAAC;IAEF,0CAA0C;IAC1C,SAAS,CAAC,GAAG,EAAE;QACX,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YAClC,QAAQ,CAAC,eAAe,CAAC,IAAI,GAAG,MAAM,CAAC;QAC3C,CAAC;IACL,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO,CACH,KAAC,kBAAkB,CAAC,QAAQ,IAAC,KAAK,EAAE,YAAY,YAC3C,QAAQ,GACiB,CACjC,CAAC;AACN,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,qBAAqB;IACjC,MAAM,GAAG,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC;IAC3C,IAAI,CAAC,GAAG;QACJ,MAAM,IAAI,KAAK,CACX,iEAAiE,CACpE,CAAC;IACN,OAAO,GAAG,CAAC;AACf,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@translation-cms/sync",
3
- "version": "1.1.59",
3
+ "version": "1.1.61",
4
4
  "description": "Scan translation keys in your codebase and sync them to the Translations CMS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,6 +16,10 @@
16
16
  "import": "./dist/use-translation.js",
17
17
  "types": "./dist/use-translation.d.ts"
18
18
  },
19
+ "./translation-provider": {
20
+ "import": "./dist/translation-provider.js",
21
+ "types": "./dist/translation-provider.d.ts"
22
+ },
19
23
  "./cli": {
20
24
  "import": "./dist/cli-utils.js",
21
25
  "types": "./dist/cli-utils.d.ts"