@umituz/react-native-localization 1.11.0 → 1.12.0

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
@@ -12,6 +12,36 @@ English-only localization system for React Native apps with i18n support. Built
12
12
  - **Zero Configuration**: Works out of the box with sensible defaults
13
13
  - **Production Ready**: Battle-tested in production apps
14
14
  - **Lightweight**: Minimal dependencies with tree-shakeable exports
15
+ - **Domain-Driven Design**: Follows DDD principles with clear separation of concerns
16
+
17
+ ## Architecture Overview
18
+
19
+ This package follows Domain-Driven Design principles:
20
+
21
+ ```
22
+ 📁 src/
23
+ ├── domain/ # Business entities and interfaces
24
+ ├── infrastructure/ # Storage, config, and external services
25
+ └── presentation/ # Hooks and components for UI
26
+ ```
27
+
28
+ ### Package vs Project Translations
29
+
30
+ **Package Translations (This Package):**
31
+ - Core UI translations (buttons, alerts, navigation)
32
+ - Device-specific translations (camera, location, etc.)
33
+ - Generic business logic translations
34
+
35
+ **Project Translations (Your App):**
36
+ - App-specific translations
37
+ - Business domain translations
38
+ - Feature-specific content
39
+
40
+ **Why This Separation?**
41
+ - Package stays lightweight and reusable
42
+ - Projects maintain full control over their translations
43
+ - Easy updates without affecting project-specific content
44
+ - Clear separation of concerns
15
45
 
16
46
  ## Installation
17
47
 
@@ -33,10 +63,143 @@ npm install zustand i18next react-i18next expo-localization @umituz/react-native
33
63
 
34
64
  ## Quick Start
35
65
 
36
- ### 1. Wrap Your App with LocalizationProvider
66
+ ### Step 1: Install Package Translations (Core UI)
67
+
68
+ ```bash
69
+ npm install @umituz/react-native-localization
70
+ ```
71
+
72
+ ### Step 2: Create Your Project's Localization Domain
73
+
74
+ Create a localization domain in your project following DDD principles:
75
+
76
+ ```
77
+ 📁 src/domains/localization/
78
+ ├── index.ts # Domain exports
79
+ ├── infrastructure/
80
+ │ ├── locales/
81
+ │ │ ├── en-US/
82
+ │ │ │ ├── index.ts # Auto-loader (uses filesystem package)
83
+ │ │ │ ├── auth.json # Authentication translations
84
+ │ │ │ ├── home.json # Home screen translations
85
+ │ │ │ ├── settings.json # Settings translations
86
+ │ │ │ └── [feature].json # Feature-specific translations
87
+ │ │ └── [other-languages]/ # Future language support
88
+ │ └── config/
89
+ │ └── i18n.ts # Project i18n configuration
90
+ └── presentation/
91
+ └── hooks/
92
+ └── useLocalization.ts # Project-specific hooks (optional)
93
+ ```
94
+
95
+ **Example from Vivoim App:**
96
+ ```
97
+ 📁 src/domains/localization/
98
+ ├── index.ts
99
+ └── infrastructure/
100
+ └── locales/
101
+ └── en-US/
102
+ ├── auth.json # Login, signup, password
103
+ ├── chat.json # Chat messages, typing
104
+ ├── common.json # Shared UI elements
105
+ ├── community.json # Social features
106
+ ├── creations.json # Content creation
107
+ ├── editor.json # Image/video editing
108
+ ├── home.json # Dashboard, navigation
109
+ ├── index.ts # Auto-loader
110
+ ├── navigation.json # App navigation
111
+ ├── paywall.json # Subscription features
112
+ ├── premium.json # Premium content
113
+ ├── profile.json # User profiles
114
+ ├── projects.json # Project management
115
+ ├── settings.json # App settings
116
+ ├── support.json # Help & support
117
+ ├── templates.json # Content templates
118
+ ├── text2image.json # AI image generation
119
+ └── wallet.json # Payments, credits
120
+ ```
121
+
122
+ **Why This Structure?**
123
+ - **Separation of Concerns**: Package handles core UI, project handles business logic
124
+ - **Scalability**: Easy to add new features without touching core package
125
+ - **Maintainability**: Clear ownership of translations
126
+ - **Reusability**: Same package works across hundreds of apps
127
+
128
+ ### Step 3: Set Up Project Translations
129
+
130
+ **src/domains/localization/infrastructure/locales/en-US/index.ts:**
131
+ ```typescript
132
+ import { loadJsonModules } from "@umituz/react-native-filesystem";
133
+
134
+ // Metro bundler require.context - auto-discover all .json files
135
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
136
+ const translationContext = (require as any).context("./", false, /\.json$/);
137
+
138
+ // Load all JSON modules using filesystem package utilities
139
+ const translations = loadJsonModules(translationContext);
140
+
141
+ export default translations;
142
+ ```
143
+
144
+ **src/domains/localization/infrastructure/locales/en-US/your-feature.json:**
145
+ ```json
146
+ {
147
+ "title": "Your Feature Title",
148
+ "description": "Feature description",
149
+ "button": {
150
+ "save": "Save Changes",
151
+ "cancel": "Cancel"
152
+ }
153
+ }
154
+ ```
155
+
156
+ ### Step 4: Configure Project i18n
157
+
158
+ **src/domains/localization/infrastructure/config/i18n.ts:**
159
+ ```typescript
160
+ import i18n from 'i18next';
161
+ import { initReactI18next } from 'react-i18next';
162
+ import { DEFAULT_LANGUAGE } from '@umituz/react-native-localization';
163
+
164
+ // Load project translations
165
+ const loadProjectTranslations = () => {
166
+ try {
167
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
168
+ return require('../locales/en-US');
169
+ } catch {
170
+ return {};
171
+ }
172
+ };
173
+
174
+ const projectTranslations = loadProjectTranslations();
175
+
176
+ // Configure i18n with project translations
177
+ i18n
178
+ .use(initReactI18next)
179
+ .init({
180
+ resources: {
181
+ 'en-US': {
182
+ translation: projectTranslations.default || projectTranslations
183
+ }
184
+ },
185
+ lng: DEFAULT_LANGUAGE,
186
+ fallbackLng: DEFAULT_LANGUAGE,
187
+ interpolation: {
188
+ escapeValue: false,
189
+ },
190
+ react: {
191
+ useSuspense: false,
192
+ },
193
+ });
194
+
195
+ export default i18n;
196
+ ```
197
+
198
+ ### Step 5: Wrap Your App
37
199
 
38
200
  ```tsx
39
201
  import { LocalizationProvider } from '@umituz/react-native-localization';
202
+ import './domains/localization/infrastructure/config/i18n'; // Initialize project i18n
40
203
 
41
204
  export default function App() {
42
205
  return (
@@ -47,7 +210,89 @@ export default function App() {
47
210
  }
48
211
  ```
49
212
 
50
- ### 2. Use Localization in Your Components
213
+ ### Step 6: Use in Components
214
+
215
+ **Option A: Use Package Localization (Recommended for UI components)**
216
+ ```tsx
217
+ import { useLocalization } from '@umituz/react-native-localization';
218
+
219
+ function MyComponent() {
220
+ const { t } = useLocalization();
221
+
222
+ return (
223
+ <View>
224
+ <Text>{t('general.save')}</Text> {/* From package */}
225
+ <Text>{t('yourFeature.title')}</Text> {/* From your project */}
226
+ </View>
227
+ );
228
+ }
229
+ ```
230
+
231
+ **Option B: Use Project Localization (For business logic)**
232
+ ```tsx
233
+ import { useTranslation } from 'react-i18next';
234
+
235
+ function MyComponent() {
236
+ const { t } = useTranslation();
237
+
238
+ return (
239
+ <View>
240
+ <Text>{t('yourFeature.title')}</Text> {/* From your project */}
241
+ </View>
242
+ );
243
+ }
244
+ ```
245
+
246
+ ### Step 7: Translation Management
247
+
248
+ #### Adding New Translations
249
+
250
+ 1. **Create JSON file** in `src/domains/localization/infrastructure/locales/en-US/`
251
+ 2. **Add translations** following flat or nested structure
252
+ 3. **Auto-loading** happens automatically via `index.ts`
253
+
254
+ #### Translation File Structure
255
+
256
+ **Flat Structure (Recommended for simple features):**
257
+ ```json
258
+ // settings.json
259
+ {
260
+ "title": "Settings",
261
+ "language": "Language",
262
+ "theme": "Theme",
263
+ "notifications": "Notifications"
264
+ }
265
+ ```
266
+
267
+ **Nested Structure (For complex features):**
268
+ ```json
269
+ // auth.json
270
+ {
271
+ "login": {
272
+ "title": "Welcome Back",
273
+ "email": "Email Address",
274
+ "password": "Password",
275
+ "forgotPassword": "Forgot Password?",
276
+ "signIn": "Sign In"
277
+ },
278
+ "register": {
279
+ "title": "Create Account",
280
+ "confirmPassword": "Confirm Password",
281
+ "signUp": "Sign Up"
282
+ }
283
+ }
284
+ ```
285
+
286
+ #### Usage in Components
287
+
288
+ ```tsx
289
+ // Flat structure
290
+ t('settings.title') // "Settings"
291
+
292
+ // Nested structure
293
+ t('auth.login.title') // "Welcome Back"
294
+ t('auth.register.signUp') // "Sign Up"
295
+ ```
51
296
 
52
297
  ```tsx
53
298
  import { useLocalization } from '@umituz/react-native-localization';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-localization",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "English-only localization system for React Native apps with i18n support",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -31,33 +31,14 @@ const packageTranslations = loadPackageTranslations();
31
31
 
32
32
  /**
33
33
  * Load project translations for all supported languages
34
- * Simple approach: try to load nutrition translations directly
34
+ * This function is a placeholder for future extensibility
35
+ * Currently returns empty translations as projects should manage their own translations
35
36
  */
36
37
  const loadProjectTranslations = (): Record<string, any> => {
37
- const translations: Record<string, any> = {};
38
-
39
- // Try to load nutrition translations from nutrition tracker app
40
- try {
41
- // Direct require for nutrition translations
42
- // eslint-disable-next-line @typescript-eslint/no-require-imports
43
- const nutritionTranslations = require('../../../../../../src/locales/en-US');
44
- if (nutritionTranslations?.default || nutritionTranslations) {
45
- translations['en-US'] = nutritionTranslations.default || nutritionTranslations;
46
- }
47
- } catch (error) {
48
- // If nutrition translations not found, try to load them directly
49
- try {
50
- // eslint-disable-next-line @typescript-eslint/no-require-imports
51
- const nutritionJson = require('../../../../../../src/locales/en-US/nutrition.json');
52
- if (nutritionJson) {
53
- translations['en-US'] = { nutrition: nutritionJson };
54
- }
55
- } catch (fallbackError) {
56
- // Silent fallback - no nutrition translations available
57
- }
58
- }
59
-
60
- return translations;
38
+ // Projects should create their own localization domains
39
+ // and manage translations within their app structure
40
+ // This package provides only the core i18n infrastructure
41
+ return {};
61
42
  };
62
43
 
63
44
  const projectTranslations = loadProjectTranslations();
@@ -103,33 +84,17 @@ const mergeTranslations = (packageTranslations: any, projectTranslations: any):
103
84
  const buildResources = (): Record<string, { translation: any }> => {
104
85
  const resources: Record<string, { translation: any }> = {};
105
86
 
106
- // Try to load nutrition translations directly for en-US
107
- let nutritionTranslations: any = {};
108
- try {
109
- // eslint-disable-next-line @typescript-eslint/no-require-imports
110
- const nutritionJson = require('../../../../../../src/locales/en-US/nutrition.json');
111
- if (nutritionJson) {
112
- nutritionTranslations = { nutrition: nutritionJson };
113
- }
114
- } catch (error) {
115
- // Silent fallback - no nutrition translations
116
- }
117
-
118
87
  // Build resources for each supported language
119
88
  for (const lang of SUPPORTED_LANGUAGES) {
120
89
  const langCode = lang.code;
121
90
  const packageTranslation = langCode === 'en-US' ? (packageTranslations['en-US'] || {}) : {};
122
91
  const projectTranslation = projectTranslations[langCode] || {};
123
92
 
124
- // For en-US, merge package, project, and nutrition translations
93
+ // For en-US, merge package and project translations
125
94
  // For other languages, use project translations only (fallback to en-US handled by i18n)
126
95
  if (langCode === 'en-US') {
127
- const mergedTranslation = mergeTranslations(
128
- mergeTranslations(packageTranslation, projectTranslation),
129
- nutritionTranslations
130
- );
131
96
  resources[langCode] = {
132
- translation: mergedTranslation,
97
+ translation: mergeTranslations(packageTranslation, projectTranslation),
133
98
  };
134
99
  } else if (projectTranslation && Object.keys(projectTranslation).length > 0) {
135
100
  resources[langCode] = {
@@ -140,9 +105,8 @@ const buildResources = (): Record<string, { translation: any }> => {
140
105
 
141
106
  // Ensure en-US is always present
142
107
  if (!resources['en-US']) {
143
- const baseTranslation = packageTranslations['en-US'] || {};
144
108
  resources['en-US'] = {
145
- translation: mergeTranslations(baseTranslation, nutritionTranslations),
109
+ translation: packageTranslations['en-US'] || {},
146
110
  };
147
111
  }
148
112