@umituz/react-native-localization 2.8.0 → 3.0.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.
Files changed (49) hide show
  1. package/package.json +22 -11
  2. package/scripts/prepublish.js +29 -16
  3. package/src/domain/repositories/ILocalizationRepository.ts +2 -2
  4. package/src/index.ts +2 -1
  5. package/src/infrastructure/components/LanguageSwitcher.tsx +90 -37
  6. package/src/infrastructure/components/LocalizationProvider.tsx +115 -7
  7. package/src/infrastructure/components/__tests__/LanguageSwitcher.test.tsx +91 -0
  8. package/src/infrastructure/components/useLanguageNavigation.ts +4 -4
  9. package/src/infrastructure/config/TranslationCache.ts +27 -0
  10. package/src/infrastructure/config/TranslationLoader.ts +4 -8
  11. package/src/infrastructure/config/__tests__/TranslationCache.test.ts +44 -0
  12. package/src/infrastructure/config/__tests__/languagesData.test.ts +49 -0
  13. package/src/infrastructure/config/languages.ts +1 -1
  14. package/src/infrastructure/config/languagesData.ts +91 -61
  15. package/src/infrastructure/hooks/__tests__/useTranslation.test.ts +52 -0
  16. package/src/infrastructure/hooks/useLocalization.ts +58 -0
  17. package/src/infrastructure/hooks/useTranslation.ts +84 -29
  18. package/src/infrastructure/storage/LanguageInitializer.ts +7 -5
  19. package/src/infrastructure/storage/LanguageSwitcher.ts +3 -3
  20. package/src/infrastructure/storage/LocalizationStore.ts +103 -94
  21. package/src/infrastructure/storage/types/LocalizationState.ts +31 -0
  22. package/src/presentation/components/LanguageItem.tsx +109 -0
  23. package/src/presentation/components/SearchInput.tsx +90 -0
  24. package/src/presentation/components/__tests__/LanguageItem.test.tsx +106 -0
  25. package/src/presentation/components/__tests__/SearchInput.test.tsx +95 -0
  26. package/src/presentation/screens/LanguageSelectionScreen.tsx +90 -146
  27. package/src/presentation/screens/__tests__/LanguageSelectionScreen.test.tsx +166 -0
  28. package/src/scripts/prepublish.ts +48 -0
  29. package/src/infrastructure/locales/en-US/alerts.json +0 -107
  30. package/src/infrastructure/locales/en-US/auth.json +0 -34
  31. package/src/infrastructure/locales/en-US/branding.json +0 -8
  32. package/src/infrastructure/locales/en-US/clipboard.json +0 -9
  33. package/src/infrastructure/locales/en-US/common.json +0 -57
  34. package/src/infrastructure/locales/en-US/datetime.json +0 -138
  35. package/src/infrastructure/locales/en-US/device.json +0 -14
  36. package/src/infrastructure/locales/en-US/editor.json +0 -64
  37. package/src/infrastructure/locales/en-US/errors.json +0 -41
  38. package/src/infrastructure/locales/en-US/general.json +0 -57
  39. package/src/infrastructure/locales/en-US/goals.json +0 -5
  40. package/src/infrastructure/locales/en-US/haptics.json +0 -6
  41. package/src/infrastructure/locales/en-US/home.json +0 -62
  42. package/src/infrastructure/locales/en-US/index.ts +0 -54
  43. package/src/infrastructure/locales/en-US/navigation.json +0 -6
  44. package/src/infrastructure/locales/en-US/onboarding.json +0 -26
  45. package/src/infrastructure/locales/en-US/projects.json +0 -34
  46. package/src/infrastructure/locales/en-US/settings.json +0 -45
  47. package/src/infrastructure/locales/en-US/sharing.json +0 -8
  48. package/src/infrastructure/locales/en-US/templates.json +0 -28
  49. package/src/infrastructure/scripts/createLocaleLoaders.js +0 -177
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Language picker with search functionality
5
5
  *
6
- * App Factory - Universal Language Selector
6
+ * Generic language selector that can be customized by consuming applications
7
7
  */
8
8
 
9
9
  import React, { useState, useMemo } from 'react';
@@ -11,25 +11,68 @@ import {
11
11
  View,
12
12
  StyleSheet,
13
13
  FlatList,
14
- TouchableOpacity,
15
- TextInput,
16
14
  } from 'react-native';
15
+ // @ts-ignore - Optional peer dependency
17
16
  import { useNavigation } from '@react-navigation/native';
18
- import { useAppDesignTokens, withAlpha, STATIC_TOKENS, type DesignTokens } from '@umituz/react-native-design-system-theme';
19
- import { AtomicIcon, AtomicText } from '@umituz/react-native-design-system-atoms';
20
- import { ScreenLayout } from '@umituz/react-native-design-system-organisms';
21
- import { useLocalization, searchLanguages, Language, LANGUAGES } from '@umituz/react-native-localization';
17
+ import { useLocalization, searchLanguages, Language } from '../../index';
18
+ import { LanguageItem } from '../components/LanguageItem';
19
+ import { SearchInput } from '../components/SearchInput';
20
+
21
+ interface LanguageSelectionScreenProps {
22
+ /**
23
+ * Custom component for rendering language items
24
+ */
25
+ renderLanguageItem?: (item: Language, isSelected: boolean, onSelect: (code: string) => void) => React.ReactNode;
26
+ /**
27
+ * Custom component for search input
28
+ */
29
+ renderSearchInput?: (value: string, onChange: (value: string) => void, placeholder: string) => React.ReactNode;
30
+ /**
31
+ * Custom component for container
32
+ */
33
+ containerComponent?: React.ComponentType<{ children: React.ReactNode }>;
34
+ /**
35
+ * Custom styles
36
+ */
37
+ styles?: {
38
+ container?: any;
39
+ searchContainer?: any;
40
+ languageItem?: any;
41
+ languageContent?: any;
42
+ languageText?: any;
43
+ flag?: any;
44
+ nativeName?: any;
45
+ searchInput?: any;
46
+ searchIcon?: any;
47
+ clearButton?: any;
48
+ listContent?: any;
49
+ };
50
+ /**
51
+ * Search placeholder text
52
+ */
53
+ searchPlaceholder: string;
54
+ /**
55
+ * Test ID for testing
56
+ */
57
+ testID?: string;
58
+ }
22
59
 
23
60
  /**
24
61
  * Language Selection Screen Component
62
+ * Generic language selector that can be customized by consuming applications
25
63
  */
26
- export const LanguageSelectionScreen: React.FC = () => {
64
+ export const LanguageSelectionScreen: React.FC<LanguageSelectionScreenProps> = ({
65
+ renderLanguageItem,
66
+ renderSearchInput,
67
+ containerComponent: Container,
68
+ styles: customStyles,
69
+ searchPlaceholder,
70
+ testID = 'language-selection-screen',
71
+ }) => {
27
72
  const navigation = useNavigation();
28
73
  const { t, currentLanguage, setLanguage } = useLocalization();
29
- const tokens = useAppDesignTokens();
30
74
  const [searchQuery, setSearchQuery] = useState('');
31
75
  const [selectedCode, setSelectedCode] = useState(currentLanguage);
32
- const [isFocused, setIsFocused] = useState(false);
33
76
 
34
77
  const filteredLanguages = useMemo(() => {
35
78
  return searchLanguages(searchQuery);
@@ -41,164 +84,65 @@ export const LanguageSelectionScreen: React.FC = () => {
41
84
  navigation.goBack();
42
85
  };
43
86
 
44
- const renderLanguageItem = ({ item }: { item: Language }) => {
87
+ const renderItem = ({ item }: { item: Language }) => {
45
88
  const isSelected = selectedCode === item.code;
46
89
 
90
+ if (renderLanguageItem) {
91
+ const customItem = renderLanguageItem(item, isSelected, handleLanguageSelect);
92
+ return <>{customItem}</>;
93
+ }
94
+
47
95
  return (
48
- <TouchableOpacity
49
- style={StyleSheet.flatten([
50
- styles.languageItem,
51
- {
52
- borderColor: isSelected
53
- ? tokens.colors.primary
54
- : tokens.colors.borderLight,
55
- backgroundColor: isSelected
56
- ? withAlpha(tokens.colors.primary, 0.1)
57
- : tokens.colors.surface,
58
- },
59
- ])}
60
- onPress={() => handleLanguageSelect(item.code)}
61
- activeOpacity={0.7}
62
- >
63
- <View style={styles.languageContent}>
64
- <AtomicText style={StyleSheet.flatten([STATIC_TOKENS.typography.headingLarge, styles.flag])}>
65
- {item.flag}
66
- </AtomicText>
67
- <View style={styles.languageText}>
68
- <AtomicText
69
- style={StyleSheet.flatten([
70
- STATIC_TOKENS.typography.bodyMedium,
71
- styles.nativeName,
72
- ])}
73
- >
74
- {item.nativeName}
75
- </AtomicText>
76
- <AtomicText style={StyleSheet.flatten([{ color: tokens.colors.textSecondary }])}>
77
- {item.name}
78
- </AtomicText>
79
- </View>
80
- </View>
81
- {isSelected && (
82
- <AtomicIcon
83
- name="CircleCheck"
84
- size="md"
85
- color="primary"
86
- />
87
- )}
88
- </TouchableOpacity>
96
+ <LanguageItem
97
+ item={item}
98
+ isSelected={isSelected}
99
+ onSelect={handleLanguageSelect}
100
+ customStyles={customStyles}
101
+ />
89
102
  );
90
103
  };
91
104
 
92
- return (
93
- <ScreenLayout scrollable={false} testID="language-selection-screen">
94
- {/* Search Input */}
95
- <View
96
- style={StyleSheet.flatten([
97
- styles.searchContainer,
98
- {
99
- borderColor: isFocused ? tokens.colors.primary : tokens.colors.borderLight,
100
- borderWidth: isFocused ? 2 : 1.5,
101
- backgroundColor: tokens.colors.surface,
102
- },
103
- ])}
104
- >
105
- <AtomicIcon
106
- name="Search"
107
- size="md"
108
- color="secondary"
109
- style={styles.searchIcon}
110
- />
111
- <TextInput
112
- style={StyleSheet.flatten([styles.searchInput, { color: tokens.colors.textPrimary }])}
113
- placeholder={t('settings.languageSelection.searchPlaceholder')}
114
- placeholderTextColor={tokens.colors.textSecondary}
115
- value={searchQuery}
116
- onChangeText={setSearchQuery}
117
- onFocus={() => setIsFocused(true)}
118
- onBlur={() => setIsFocused(false)}
119
- autoCapitalize="none"
120
- autoCorrect={false}
121
- />
122
- {searchQuery.length > 0 && (
123
- <TouchableOpacity
124
- onPress={() => setSearchQuery('')}
125
- style={styles.clearButton}
126
- hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
127
- >
128
- <AtomicIcon
129
- name="X"
130
- size="sm"
131
- color="secondary"
132
- />
133
- </TouchableOpacity>
134
- )}
135
- </View>
105
+ const renderSearchInputComponent = () => {
106
+ if (renderSearchInput) {
107
+ return renderSearchInput(searchQuery, setSearchQuery, searchPlaceholder);
108
+ }
136
109
 
137
- {/* Language List */}
110
+ return (
111
+ <SearchInput
112
+ value={searchQuery}
113
+ onChange={setSearchQuery}
114
+ placeholder={searchPlaceholder}
115
+ customStyles={customStyles}
116
+ />
117
+ );
118
+ };
119
+
120
+ const content = (
121
+ <View style={[styles.container, customStyles?.container]} testID={testID}>
122
+ {renderSearchInputComponent()}
138
123
  <FlatList
139
124
  data={filteredLanguages}
140
- renderItem={renderLanguageItem}
125
+ renderItem={renderItem}
141
126
  keyExtractor={item => item.code}
142
- contentContainerStyle={styles.listContent}
127
+ contentContainerStyle={[styles.listContent, customStyles?.listContent]}
143
128
  showsVerticalScrollIndicator={false}
144
129
  keyboardShouldPersistTaps="handled"
145
130
  />
146
- </ScreenLayout>
131
+ </View>
147
132
  );
133
+
134
+ return Container ? <Container>{content}</Container> : content;
148
135
  };
149
136
 
150
137
  const styles = StyleSheet.create({
151
- searchContainer: {
152
- flexDirection: 'row',
153
- alignItems: 'center',
154
- marginHorizontal: 20,
155
- marginBottom: 24,
156
- paddingHorizontal: 16,
157
- paddingVertical: 8,
158
- borderRadius: STATIC_TOKENS.borders.radius.lg,
159
- },
160
- searchIcon: {
161
- marginRight: 8,
162
- },
163
- searchInput: {
138
+ container: {
164
139
  flex: 1,
165
- fontSize: STATIC_TOKENS.typography.bodyMedium.fontSize,
166
- padding: 0,
167
- fontWeight: '500',
168
- },
169
- clearButton: {
170
- padding: STATIC_TOKENS.spacing.xs,
140
+ backgroundColor: '#fff',
171
141
  },
172
142
  listContent: {
173
143
  paddingHorizontal: 20,
174
144
  paddingBottom: 32,
175
145
  },
176
- languageItem: {
177
- flexDirection: 'row',
178
- alignItems: 'center',
179
- justifyContent: 'space-between',
180
- padding: STATIC_TOKENS.spacing.md,
181
- borderRadius: STATIC_TOKENS.borders.radius.lg,
182
- borderWidth: 2,
183
- marginBottom: 8,
184
- },
185
- languageContent: {
186
- flexDirection: 'row',
187
- alignItems: 'center',
188
- flex: 1,
189
- gap: 16,
190
- },
191
- flag: {
192
- fontSize: STATIC_TOKENS.typography.headingLarge.fontSize,
193
- },
194
- languageText: {
195
- flex: 1,
196
- gap: 2,
197
- },
198
- nativeName: {
199
- fontWeight: '600',
200
- },
201
146
  });
202
147
 
203
- export default LanguageSelectionScreen;
204
-
148
+ export default LanguageSelectionScreen;
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Language Selection Screen Tests
3
+ */
4
+
5
+ import React from 'react';
6
+ import { render, fireEvent } from '@testing-library/react-native';
7
+ import { LanguageSelectionScreen } from '../LanguageSelectionScreen';
8
+ import { useLocalization } from '../../infrastructure/hooks/useLocalization';
9
+ import { searchLanguages } from '../../infrastructure/config/languagesData';
10
+
11
+ // Mock dependencies
12
+ jest.mock('../../infrastructure/hooks/useLocalization');
13
+ jest.mock('../../infrastructure/config/languagesData');
14
+ jest.mock('@react-navigation/native', () => ({
15
+ useNavigation: () => ({
16
+ goBack: jest.fn(),
17
+ }),
18
+ }));
19
+
20
+ const mockUseLocalization = useLocalization as jest.MockedFunction<typeof useLocalization>;
21
+ const mockSearchLanguages = searchLanguages as jest.MockedFunction<typeof searchLanguages>;
22
+
23
+ const mockLanguage = {
24
+ code: 'en-US',
25
+ name: 'English',
26
+ nativeName: 'English',
27
+ flag: '🇺🇸',
28
+ isRTL: false,
29
+ };
30
+
31
+ describe('LanguageSelectionScreen', () => {
32
+ const mockSetLanguage = jest.fn();
33
+ const mockGoBack = jest.fn();
34
+
35
+ beforeEach(() => {
36
+ jest.clearAllMocks();
37
+
38
+ mockUseLocalization.mockReturnValue({
39
+ currentLanguage: 'en-US',
40
+ setLanguage: mockSetLanguage,
41
+ t: jest.fn(),
42
+ } as any);
43
+
44
+ mockSearchLanguages.mockReturnValue([mockLanguage]);
45
+ });
46
+
47
+ it('should render search input and language list', () => {
48
+ const { getByPlaceholderText, getByText } = render(
49
+ <LanguageSelectionScreen
50
+ searchPlaceholder="Search languages..."
51
+ />
52
+ );
53
+
54
+ expect(getByPlaceholderText('Search languages...')).toBeTruthy();
55
+ expect(getByText('English')).toBeTruthy();
56
+ expect(getByText('🇺🇸')).toBeTruthy();
57
+ });
58
+
59
+ it('should filter languages when searching', () => {
60
+ const { getByPlaceholderText } = render(
61
+ <LanguageSelectionScreen
62
+ searchPlaceholder="Search languages..."
63
+ />
64
+ );
65
+
66
+ fireEvent.changeText(getByPlaceholderText('Search languages...'), 'test');
67
+ expect(mockSearchLanguages).toHaveBeenCalledWith('test');
68
+ });
69
+
70
+ it('should select language when item is pressed', async () => {
71
+ const { getByText } = render(
72
+ <LanguageSelectionScreen
73
+ searchPlaceholder="Search languages..."
74
+ />
75
+ );
76
+
77
+ fireEvent.press(getByText('English'));
78
+ expect(mockSetLanguage).toHaveBeenCalledWith('en-US');
79
+ });
80
+
81
+ it('should show check icon for selected language', () => {
82
+ const { getByText } = render(
83
+ <LanguageSelectionScreen
84
+ searchPlaceholder="Search languages..."
85
+ />
86
+ );
87
+
88
+ expect(getByText('✓')).toBeTruthy();
89
+ });
90
+
91
+ it('should use custom render function when provided', () => {
92
+ const customRender = jest.fn().mockReturnValue(<div>Custom Item</div>);
93
+
94
+ render(
95
+ <LanguageSelectionScreen
96
+ searchPlaceholder="Search languages..."
97
+ renderLanguageItem={customRender}
98
+ />
99
+ );
100
+
101
+ expect(customRender).toHaveBeenCalledWith(
102
+ mockLanguage,
103
+ true,
104
+ expect.any(Function)
105
+ );
106
+ });
107
+
108
+ it('should use custom search input when provided', () => {
109
+ const customSearchInput = jest.fn().mockReturnValue(<div>Custom Search</div>);
110
+
111
+ render(
112
+ <LanguageSelectionScreen
113
+ searchPlaceholder="Search languages..."
114
+ renderSearchInput={customSearchInput}
115
+ />
116
+ );
117
+
118
+ expect(customSearchInput).toHaveBeenCalledWith(
119
+ '',
120
+ expect.any(Function),
121
+ 'Search languages...'
122
+ );
123
+ });
124
+
125
+ it('should use custom container when provided', () => {
126
+ const CustomContainer = ({ children }: { children: React.ReactNode }) => (
127
+ <div testID="custom-container">{children}</div>
128
+ );
129
+
130
+ const { getByTestId } = render(
131
+ <LanguageSelectionScreen
132
+ searchPlaceholder="Search languages..."
133
+ containerComponent={CustomContainer}
134
+ />
135
+ );
136
+
137
+ expect(getByTestId('custom-container')).toBeTruthy();
138
+ });
139
+
140
+ it('should apply custom styles', () => {
141
+ const customStyles = {
142
+ container: { backgroundColor: 'red' },
143
+ languageItem: { borderColor: 'blue' },
144
+ };
145
+
146
+ const { getByTestId } = render(
147
+ <LanguageSelectionScreen
148
+ searchPlaceholder="Search languages..."
149
+ styles={customStyles}
150
+ />
151
+ );
152
+
153
+ expect(getByTestId('language-selection-screen')).toHaveStyle({ backgroundColor: 'red' });
154
+ });
155
+
156
+ it('should use custom test ID when provided', () => {
157
+ const { getByTestId } = render(
158
+ <LanguageSelectionScreen
159
+ searchPlaceholder="Search languages..."
160
+ testID="custom-test-id"
161
+ />
162
+ );
163
+
164
+ expect(getByTestId('custom-test-id')).toBeTruthy();
165
+ });
166
+ });
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+
4
+ /**
5
+ * Pre-Publish Script - Generic Package Version
6
+ *
7
+ * Basic checks before publishing for generic localization package
8
+ */
9
+
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ import { fileURLToPath } from 'url';
13
+
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
17
+ const SRC_DIR = path.join(PACKAGE_ROOT, 'src');
18
+
19
+ console.log('🔍 Pre-publish checks...\n');
20
+
21
+ // Check if src directory exists
22
+ if (!fs.existsSync(SRC_DIR)) {
23
+ console.error('❌ src directory not found!');
24
+ process.exit(1);
25
+ }
26
+
27
+ // Check if main files exist
28
+ const mainFiles = [
29
+ 'src/index.ts',
30
+ 'src/infrastructure/config/i18n.ts',
31
+ 'src/infrastructure/storage/LocalizationStore.ts',
32
+ ];
33
+
34
+ let allFilesExist = true;
35
+ for (const file of mainFiles) {
36
+ const filePath = path.join(PACKAGE_ROOT, file);
37
+ if (!fs.existsSync(filePath)) {
38
+ console.error(`❌ Required file not found: ${file}`);
39
+ allFilesExist = false;
40
+ }
41
+ }
42
+
43
+ if (!allFilesExist) {
44
+ process.exit(1);
45
+ }
46
+
47
+ console.log('✅ All required files found');
48
+ console.log('✅ Pre-publish checks passed!\n');
@@ -1,107 +0,0 @@
1
- {
2
- "error": {
3
- "title": "Error",
4
- "generic": "An error occurred",
5
- "failed_to_select_video": "Failed to select video",
6
- "failed_to_select_images": "Failed to select images",
7
- "failed_to_select_audio": "Failed to select audio file",
8
- "failed_to_generate_video": "Failed to generate video",
9
- "failed_to_transform_video": "Failed to transform video",
10
- "failed_to_generate_script": "Failed to generate script",
11
- "failed_to_export": "Export failed",
12
- "failed_to_pick_image": "Failed to pick image. Please try again.",
13
- "failed_to_take_photo": "Failed to take photo. Please try again.",
14
- "project_not_found": "Project not found",
15
- "cannot_delete_last_scene": "Cannot delete the last scene",
16
- "configuration_error": "Firebase is not configured. Please check your environment settings.",
17
- "sign_in_failed": "Failed to sign in. Please try again.",
18
- "sign_up_failed": "Failed to create account. Please try again.",
19
- "sign_in_google_failed": "Failed to sign in with Google.",
20
- "sign_up_google_failed": "Failed to sign up with Google."
21
- },
22
- "success": {
23
- "title": "Success",
24
- "project_saved": "Project saved successfully!",
25
- "text_layer_added": "Text layer added!",
26
- "text_layer_updated": "Text layer updated!",
27
- "layer_deleted": "Layer deleted",
28
- "layer_duplicated": "Layer duplicated!",
29
- "scene_added": "New scene added!",
30
- "scene_duplicated": "Scene duplicated!",
31
- "scene_deleted": "Scene deleted",
32
- "image_layer_added": "Image layer added!",
33
- "image_layer_updated": "Image layer updated!",
34
- "shape_layer_added": "Shape layer added!",
35
- "audio_added": "Audio added to scene!",
36
- "audio_removed": "Audio removed from scene",
37
- "animation_applied": "Animation applied to layer!",
38
- "animation_removed": "Animation removed from layer",
39
- "custom_audio_selected": "Custom audio selected!",
40
- "video_created": "Video Created! 🎬",
41
- "video_generated": "Video Generated! 🎉",
42
- "script_copied": "Copied!",
43
- "password_reset_sent": "Password reset link sent to your email.",
44
- "account_created": "Your account has been created successfully.",
45
- "project_deleted": "{{title}} deleted successfully",
46
- "project_duplicated": "Project duplicated: {{title}}"
47
- },
48
- "validation": {
49
- "missing_prompt": "Missing Prompt",
50
- "missing_prompt_message": "Please enter a description for your video",
51
- "missing_topic": "Missing Topic",
52
- "missing_topic_message": "Please enter a topic for your video",
53
- "missing_email": "Enter Email",
54
- "missing_email_message": "Please enter your email address first.",
55
- "enter_name": "Please enter your name",
56
- "enter_email": "Please enter your email",
57
- "enter_valid_email": "Please enter a valid email address",
58
- "enter_password": "Please enter a password",
59
- "enter_email_password": "Please enter email and password",
60
- "password_min_length": "Password must be at least 6 characters",
61
- "passwords_not_match": "Passwords do not match",
62
- "no_video_selected": "No Video",
63
- "no_video_selected_message": "Please select a video first",
64
- "no_image_selected": "No Image",
65
- "no_image_selected_message": "Please select an image first.",
66
- "no_audio_selected": "Please select an audio file"
67
- },
68
- "video": {
69
- "generation_failed": "Generation Failed",
70
- "generation_failed_message": "Unable to generate video",
71
- "transformation_failed": "Transformation Failed",
72
- "transformation_failed_message": "Unable to transform video",
73
- "video_ready": "Your AI-generated video is ready!",
74
- "video_created_message": "Created {{count}} animated scenes with {{style}} effect"
75
- },
76
- "script": {
77
- "generation_failed": "Generation Failed",
78
- "generation_failed_message": "Unable to generate script"
79
- },
80
- "export": {
81
- "title": "Export Complete",
82
- "message": "Your video has been exported successfully!\n\nLocation: {{uri}}",
83
- "failed_title": "Export Failed",
84
- "failed_message": "An error occurred during export"
85
- },
86
- "delete": {
87
- "layer_title": "Delete Layer",
88
- "layer_message": "Are you sure you want to delete this layer?",
89
- "scene_title": "Delete Scene",
90
- "scene_message": "Are you sure you want to delete this scene?"
91
- },
92
- "actions": {
93
- "undo": "Undo",
94
- "undo_message": "Action undone",
95
- "redo": "Redo",
96
- "redo_message": "Action done",
97
- "coming_soon": "Coming soon!",
98
- "export_coming_soon": "Export feature coming soon!",
99
- "share_coming_soon": "Share feature coming soon!",
100
- "effects_coming_soon": "Effects feature coming soon!"
101
- },
102
- "premium": {
103
- "upgrade_successful": "🎉 Upgrade Successful!",
104
- "upgrade_message": "Welcome to Premium! You now have unlimited access to all features.",
105
- "start_creating": "Start Creating"
106
- }
107
- }
@@ -1,34 +0,0 @@
1
- {
2
- "title": "Welcome",
3
- "subtitle": "Sign in to your account or continue as guest",
4
- "welcomeBack": "Welcome Back",
5
- "loginSubtitle": "Sign in to sync your data across devices",
6
- "email": "Email",
7
- "emailPlaceholder": "Enter your email",
8
- "password": "Password",
9
- "passwordPlaceholder": "Enter your password",
10
- "signIn": "Sign In",
11
- "createAccount": "Create Account",
12
- "continueAsGuest": "Continue as Guest",
13
- "dontHaveAccount": "Don't have an account?",
14
- "register": "Register",
15
- "displayName": "Display Name",
16
- "displayNamePlaceholder": "Enter your name",
17
- "confirmPassword": "Confirm Password",
18
- "confirmPasswordPlaceholder": "Re-enter your password",
19
- "backToLogin": "Back to Login",
20
- "registerSubtitle": "Create an account to sync your data",
21
- "fillAllFields": "Please fill in all fields",
22
- "passwordsDoNotMatch": "Passwords do not match",
23
- "passwordTooShort": "Password must be at least 6 characters",
24
- "loginFailed": "Login failed. Please check your credentials.",
25
- "registrationFailed": "Registration failed. Please try again.",
26
- "logout": "Logout",
27
- "signedInAs": "Signed in as",
28
- "guestMode": "Guest Mode",
29
- "guestModeDescription": "Your data is stored locally on this device",
30
- "syncData": "Sync Local Data",
31
- "syncDataDescription": "Upload your local data to the cloud",
32
- "syncSuccess": "Data synced successfully",
33
- "syncFailed": "Failed to sync data"
34
- }
@@ -1,8 +0,0 @@
1
- {
2
- "appName": "App Name",
3
- "tagline": "Welcome",
4
- "poweredBy": "Powered by",
5
- "splash": {
6
- "loading": "Loading..."
7
- }
8
- }
@@ -1,9 +0,0 @@
1
- {
2
- "clipboard": {
3
- "copied": "Copied",
4
- "copyFailed": "Failed to copy",
5
- "pasteFailed": "Failed to paste",
6
- "cleared": "Clipboard cleared",
7
- "empty": "Clipboard is empty"
8
- }
9
- }