import { ExpoConfig } from '@expo/config-types' ; import JsonFile from '@expo/json-file' ; import * as fs from 'fs-extra' ; import { join } from 'path' ; import { XcodeProject } from 'xcode' ; import { ConfigPlugin } from '../Plugin.types' ; import { withXcodeProject } from '../plugins/ios-plugins' ; import { addWarningIOS } from '../utils/warnings' ; import { addResourceFileToGroup , ensureGroupRecursively , getProjectName } from './utils/Xcodeproj' ; type LocaleJson = Record < string , string > ; type ResolvedLocalesJson = Record < string , LocaleJson > ; type ExpoConfigLocales = NonNullable < ExpoConfig [ 'locales' ] > ; export const withLocales = config => { return withXcodeProject ( config , async ( config ) => { config . modResults = await setLocalesAsync ( config , { projectRoot : config . modRequest . projectRoot , project : config . modResults } ) ; return config ; } ) ; } ; export function getLocales ( config ) { return config . locales ?? null ; } export async function setLocalesAsync ( config , { projectRoot , project } ) { const locales = getLocales ( config ) ; if ( ! locales ) { return project ; } const localesMap = await getResolvedLocalesAsync ( projectRoot , locales ) ; const projectName = getProjectName ( projectRoot ) ; const supportingDirectory = join ( projectRoot , 'ios' , projectName , 'Supporting' ) ; const stringName = 'InfoPlist.strings' ; for ( const [ lang , localizationObj ] of Object . entries ( localesMap ) ) { const dir = join ( supportingDirectory , `${ lang }.lproj` ) ; await fs . ensureDir ( dir ) ; const strings = join ( dir , stringName ) ; const buffer = [ ] ; for ( const [ plistKey , localVersion ] of Object . entries ( localizationObj ) ) { buffer . push ( `${ plistKey } = "${ localVersion }";` ) ; } await fs . writeFile ( strings , buffer . join ( '\n' ) ) ; const group = ensureGroupRecursively ( project , `${ projectName }/Supporting/${ lang }.lproj` ) ; if ( ! group ?. children . some ( ( { comment } ) => comment === stringName ) ) { project = addResourceFileToGroup ( { filepath : strings , groupName : `${ projectName }/Supporting/${ lang }.lproj` , project , isBuildFile : true , verbose : true } ) ; } } return project ; } export async function getResolvedLocalesAsync ( projectRoot , input ) { const locales = { } ; for ( const [ lang , localeJsonPath ] of Object . entries ( input ) ) { if ( typeof localeJsonPath === 'string' ) { try { locales [ lang ] = await JsonFile . readAsync ( join ( projectRoot , localeJsonPath ) ) ; } catch ( e ) { addWarningIOS ( `locales.${ lang }` , `Failed to parse JSON of locale file for language: ${ lang }` , 'https://docs.expo.dev/distribution/app-stores/#localizing-your-ios-app' ) ; } } else { locales [ lang ] = localeJsonPath ; } } return locales ; }