diff --git a/js/LocalizedString.ts b/js/LocalizedString.ts index b232e79e8..c12c5e18f 100644 --- a/js/LocalizedString.ts +++ b/js/LocalizedString.ts @@ -92,7 +92,8 @@ class LocalizedString { * Take a state from getStateDelta, and apply it. */ public setStateDelta( state: LocalizedStringStateDelta ): void { - // Create potential new locales + + // Create potential new locales (since locale-specific Properties are lazily created as needed Object.keys( state ).forEach( locale => this.getLocaleSpecificProperty( locale ) ); this.usedLocales.forEach( locale => { @@ -137,7 +138,8 @@ class LocalizedString { } private onLocaleOrderChange( localeOrder: string[] ): void { - // Do this in reverse order to AVOID infinite loops, e.g. if localeOrder1=ar,es localeOrder2=es,ar, then we + + // Do this in reverse order to AVOID infinite loops (e.g. if localeOrder1=ar,es localeOrder2=es,ar) then we // could have both TinyOverrideProperties pointing to each other, and they wouldn't be able to get a value const locales = [ ...this.usedLocales, @@ -155,7 +157,7 @@ class LocalizedString { } /** - * Returns the locale-specific TProperty for any locale (lazily creating it if necessary) + * Returns the locale-specific Property for any locale (lazily creating it if necessary) */ public getLocaleSpecificProperty( locale: string ): TProperty { if ( locale === 'en' ) { diff --git a/js/getStringModule.ts b/js/getStringModule.ts index 7c2786a38..6e1662d97 100644 --- a/js/getStringModule.ts +++ b/js/getStringModule.ts @@ -21,6 +21,7 @@ import TReadOnlyProperty from '../../axon/js/TReadOnlyProperty.js'; // constants const FALLBACK_LOCALE = 'en'; +type PhetioID = string; // Holds all of our localizedStrings, so that we can save our phet-io string change state export const localizedStrings: LocalizedString[] = []; @@ -35,7 +36,7 @@ window.phet.chipper.setAllStrings = ( str: string ) => { const StringStateIOType = new IOType( 'StringStateIO', { isValidValue: () => true, toStateObject: () => { - const data: Record = {}; + const data: Record = {}; localizedStrings.forEach( localizedString => { const state = localizedString.getStateDelta(); @@ -46,30 +47,30 @@ const StringStateIOType = new IOType( 'StringStateIO', { } } ); return { - // Data nested for a valid schema - data: data + data: data // Data nested for a valid schema }; }, stateSchema: { data: ObjectLiteralIO }, - applyState: ( ( ignored, state ) => { + applyState: ( ignored, state ) => { - // When PhetioDynamicElementContainer elements such as PhetioGroup memers add localizedStrings, we wait until - // all of the members have been created before trying to set any of the strings. - const keys = Object.keys( state.data ); - keys.forEach( key => { - const match = localizedStrings.find( localizedString => localizedString.property.tandem.phetioID === key ); + // Every string in state has to be in localizedStrings to continue + Object.keys( state.data ).forEach( phetioID => { + const match = localizedStrings.find( localizedString => localizedString.property.tandem.phetioID === phetioID ); + + // When PhetioDynamicElementContainer elements such as PhetioGroup members add localizedStrings, we wait until + // all of the members have been created (populating localizedStrings) before trying to set any of the strings. if ( !match ) { throw new CouldNotYetDeserializeError(); } } ); - // We need to iterate through every string, since it might need to revert back to "initial" state + // We need to iterate through every string in this runtime, since it might need to revert back to "initial" state. localizedStrings.forEach( localizedString => { localizedString.setStateDelta( state.data[ localizedString.property.tandem.phetioID ] || {} ); } ); - } ) + } } ); PhetioObject.create( {