diff --git a/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js b/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js index 3b31099..36b0266 100644 --- a/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js +++ b/solara/lib/core/dashboard/brand/source/BrandRemoteSource.js @@ -89,7 +89,6 @@ class BrandRemoteSource { "name": "iOS Platform Configuration", "inputType": "text", "content": { - "PRODUCT_NAME": "", "PRODUCT_BUNDLE_IDENTIFIER": "", "MARKETING_VERSION": "1.0.0", "BUNDLE_VERSION": 1, diff --git a/solara/lib/core/doctor/brand_doctor.rb b/solara/lib/core/doctor/brand_doctor.rb index f682387..7c6c180 100644 --- a/solara/lib/core/doctor/brand_doctor.rb +++ b/solara/lib/core/doctor/brand_doctor.rb @@ -17,6 +17,11 @@ def visit(brand_keys = [], print_logs: true) errors.each { |error| issues << Issue.error(error) } + + # Validate InfoPlist.xcstrings only if all validations so far are passed to avoid files issues + if issues.select { |issue| issue.type == Issue::ERROR }.empty? + issues += InfoPListStringCatalogManager.new.validate_required_keys(brand_key) + end end # Validate settings only if all validations so far are passed to avoid files issues diff --git a/solara/lib/core/doctor/schema/platform/ios/ios_config.json b/solara/lib/core/doctor/schema/platform/ios/ios_config.json index 61ec1c6..a36643a 100644 --- a/solara/lib/core/doctor/schema/platform/ios/ios_config.json +++ b/solara/lib/core/doctor/schema/platform/ios/ios_config.json @@ -1,10 +1,6 @@ { "type": "object", "properties": { - "PRODUCT_NAME": { - "type": "string", - "description": "The name of the product." - }, "PRODUCT_BUNDLE_IDENTIFIER": { "type": "string", "description": "The bundle identifier of the product." @@ -19,7 +15,6 @@ } }, "required": [ - "PRODUCT_NAME", "PRODUCT_BUNDLE_IDENTIFIER", "MARKETING_VERSION", "BUNDLE_VERSION" diff --git a/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb b/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb index 09f589a..a5e016e 100644 --- a/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb +++ b/solara/lib/core/scripts/platform/ios/infoplist_string_catalog_manager.rb @@ -16,6 +16,9 @@ def update(result, path) } } # Update the value in the JSON structure + state = value.empty? ? 'new' : 'translated' + localizations['strings'][base_key]['localizations'][lang_code]['stringUnit']['state'] = state + localizations['strings'][base_key]['localizations'][lang_code]['stringUnit']['value'] = value end end @@ -33,4 +36,71 @@ def update(result, path) File.write(path, JSON.pretty_generate(localizations)) end + def get_default_state_of(key, brand_key) + get_default_value(key, 'state', brand_key) + end + + def get_default_value_of(key, brand_key) + get_default_value(key, 'value', brand_key) + end + + def get_default_value(key, target, brand_key) + path = FilePath.brand_infoplist_string_catalog(brand_key) + + data = JSON.parse(File.read(path)) + + # Get the source language + source_language = data['sourceLanguage'] + + # Retrieve the CFBundleDisplayName localizations value + data['strings'][key]['localizations'][source_language]['stringUnit'][target] + end + + def has_bundle_name(brand_key) + get_default_state_of(InfoPListKey::BUNDLE_NAME, brand_key) != 'new' + end + + def has_bundle_display_name(brand_key) + get_default_state_of(InfoPListKey::BUNDLE_DISPLAY_NAME, brand_key) != 'new' + end + + def has_value(key, brand_key) + state = get_default_state_of(key, brand_key) + value = get_default_value_of(key, brand_key) + state != 'new' && !value.empty? + end + + def validate_required_keys(brand_key) + errors = [] + bundle_name = validate(InfoPListKey::BUNDLE_NAME, brand_key) + errors << Issue.error(bundle_name) if bundle_name + + bundle_display_name = validate(InfoPListKey::BUNDLE_DISPLAY_NAME, brand_key) + errors << Issue.error(bundle_display_name) if bundle_display_name + + errors + end + + def validate(key, brand_key) + unless has_value(key, brand_key) + message = "The value for '#{key}' is not translated in #{FilePath.brand_infoplist_string_catalog(brand_key)}. To resolve this issue, please open the dashboard and update the entry for '#{key}.#{source_language(brand_key)}'. If you prefer, you can manually add a value and mark its state as 'translated'." + return message + end + nil + end + + def source_language(brand_key) + path = FilePath.brand_infoplist_string_catalog(brand_key) + + data = JSON.parse(File.read(path)) + + # Get the source language + data['sourceLanguage'] + end + +end + +module InfoPListKey + BUNDLE_NAME = 'CFBundleName' + BUNDLE_DISPLAY_NAME = 'CFBundleDisplayName' end \ No newline at end of file diff --git a/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb b/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb index cb758e5..3e5df3c 100644 --- a/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb +++ b/solara/lib/core/scripts/platform/ios/infoplist_switcher.rb @@ -38,12 +38,17 @@ def update_info_plist manager.set_info_plist_in_build_settings xcconfig_values = { + 'CFBUNDLE_DISPLAY_NAME' => "$(CFBUNDLE_DISPLAY_NAME)", + 'CFBUNDLE_NAME' => "$(CFBUNDLE_NAME)", + 'PRODUCT_NAME' => "$(PRODUCT_NAME)", 'PRODUCT_BUNDLE_IDENTIFIER' => "$(PRODUCT_BUNDLE_IDENTIFIER)", 'MARKETING_VERSION' => "$(MARKETING_VERSION)", 'BUNDLE_VERSION' => "$(BUNDLE_VERSION)" } info_plist = Xcodeproj::Plist.read_from_path(info_plist_path) + info_plist[InfoPListKey::BUNDLE_DISPLAY_NAME] = xcconfig_values['CFBUNDLE_DISPLAY_NAME'] + info_plist[InfoPListKey::BUNDLE_NAME] = xcconfig_values['CFBUNDLE_NAME'] info_plist['CFBundleIdentifier'] = xcconfig_values['PRODUCT_BUNDLE_IDENTIFIER'] info_plist['CFBundleShortVersionString'] = xcconfig_values['MARKETING_VERSION'] info_plist['CFBundleVersion'] = xcconfig_values['BUNDLE_VERSION'] diff --git a/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb b/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb index 83efe1e..25defbc 100644 --- a/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb +++ b/solara/lib/core/scripts/platform/ios/xcconfig_generator.rb @@ -19,6 +19,9 @@ def generate def generate_xcconfig_content content = <<~XCCONFIG ASSETCATALOG_COMPILER_APPICON_NAME = #{FilePath.artifacts_dir_name_ios}/AppIcon + PRODUCT_NAME = #{get_value_of(InfoPListKey::BUNDLE_DISPLAY_NAME)} + CFBUNDLE_DISPLAY_NAME = #{get_value_of(InfoPListKey::BUNDLE_DISPLAY_NAME)} + CFBUNDLE_NAME = #{get_value_of(InfoPListKey::BUNDLE_NAME)} #{load_config.map { |key, value| "#{key.upcase} = #{value}" }.join("\n")} XCCONFIG @@ -37,6 +40,10 @@ def generate_xcconfig_content end end + def get_value_of(key) + InfoPListStringCatalogManager.new.get_default_value_of(key, @brand_key) + end + def load_config config_path = FilePath.ios_config(@brand_key) JSON.parse(File.read(config_path)) diff --git a/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb b/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb index b17a8df..e540f72 100644 --- a/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb +++ b/solara/lib/core/scripts/platform/ios/xcode_project_switcher.rb @@ -24,6 +24,7 @@ def update_xcode_target_settings config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = '$(PRODUCT_BUNDLE_IDENTIFIER)' config.build_settings['MARKETING_VERSION'] = '$(MARKETING_VERSION)' config.build_settings['ASSETCATALOG_COMPILER_APPICON_NAME'] = "$(#{FilePath.artifacts_dir_name_ios}/AppIcon)" + config.build_settings['PRODUCT_NAME'] = '$(PRODUCT_NAME)' # We need to apply code signing only if the user has provided its config path = FilePath.brand_signing(@brand_key, Platform::IOS) diff --git a/solara/lib/core/template/brands/ios/ios_config.json b/solara/lib/core/template/brands/ios/ios_config.json index 35123d1..d69f8df 100644 --- a/solara/lib/core/template/brands/ios/ios_config.json +++ b/solara/lib/core/template/brands/ios/ios_config.json @@ -1,5 +1,4 @@ { - "PRODUCT_NAME": "", "PRODUCT_BUNDLE_IDENTIFIER": "", "MARKETING_VERSION": "1.0.0", "BUNDLE_VERSION": 1, diff --git a/solara/lib/solara.rb b/solara/lib/solara.rb index 997661b..6aae48f 100644 --- a/solara/lib/solara.rb +++ b/solara/lib/solara.rb @@ -143,7 +143,6 @@ def switch begin SolaraManager.new.switch(brand_key) rescue StandardError => e - Solara.logger.error(e) Solara.logger.fatal("Switching to #{brand_key} failed.") exit 1 end