old_contents: #!/usr/bin/env python3
  """Merge all translation sources into a single JSON file."""
  import glob
  import itertools
  import json
  import os
  import re
  from typing import Union, List, Dict
  
  FILENAME_FORMAT = re.compile(r'strings\.(?P<suffix>\w+)\.json')
  
  
  def load_json(filename: str) \
          -> Union[List, Dict]:
      """Load JSON data from a file and return as dict or list.
  
      Defaults to returning empty dict if file is not found.
      """
      with open(filename, encoding='utf-8') as fdesc:
          return json.loads(fdesc.read())
      return {}
  
  
  def save_json(filename: str, data: Union[List, Dict]):
      """Save JSON data to a file.
  
      Returns True on success.
      """
      data = json.dumps(data, sort_keys=True, indent=4)
      with open(filename, 'w', encoding='utf-8') as fdesc:
          fdesc.write(data)
          return True
      return False
  
  
  def find_strings_files():
      """Return the paths of the strings source files."""
      return itertools.chain(
          glob.iglob("strings*.json"),
          glob.iglob("*{}strings*.json".format(os.sep)),
      )
  
  
  def get_component_platform(path):
      """Get the component and platform name from the path."""
      directory, filename = os.path.split(path)
      match = FILENAME_FORMAT.search(filename)
      suffix = match.group('suffix') if match else None
      if directory:
          return directory, suffix
      else:
          return suffix, None
  
  
  def get_translation_dict(translations, component, platform):
      """Return the dict to hold component translations."""
      if not component:
          return translations['component']
  
      if component not in translations:
          translations['component'][component] = {}
  
      if not platform:
          return translations['component'][component]
  
      if 'platform' not in translations['component'][component]:
          translations['component'][component]['platform'] = {}
  
      if platform not in translations['component'][component]['platform']:
          translations['component'][component]['platform'][platform] = {}
  
      return translations['component'][component]['platform'][platform]
  
  
  def main():
      """Main section of the script."""
      if not os.path.isfile("requirements_all.txt"):
          print("Run this from HA root dir")
          return
  
      root = os.getcwd()
      os.chdir(os.path.join("homeassistant", "components"))
  
      translations = {
          'component': {}
      }
  
      paths = find_strings_files()
      for path in paths:
          component, platform = get_component_platform(path)
          parent = get_translation_dict(translations, component, platform)
          strings = load_json(path)
          parent.update(strings)
  
      os.chdir(root)
  
      os.makedirs("build", exist_ok=True)
  
      save_json(
          os.path.join("build", "translations-upload.json"), translations)
  
  
  if __name__ == '__main__':
      main()
  
new_contents: #!/usr/bin/env python3
  """Merge all translation sources into a single JSON file."""
  import glob
  import itertools
  import json
  import os
  import re
  from typing import Union, List, Dict
  
  FILENAME_FORMAT = re.compile(r'strings\.(?P<suffix>\w+)\.json')
  
  
  def load_json(filename: str) \
          -> Union[List, Dict]:
      """Load JSON data from a file and return as dict or list.
  
      Defaults to returning empty dict if file is not found.
      """
      with open(filename, encoding='utf-8') as fdesc:
          return json.loads(fdesc.read())
      return {}
  
  
  def save_json(filename: str, data: Union[List, Dict]):
      """Save JSON data to a file.
  
      Returns True on success.
      """
      data = json.dumps(data, sort_keys=True, indent=4)
      with open(filename, 'w', encoding='utf-8') as fdesc:
          fdesc.write(data)
          return True
      return False
  
  
  def find_strings_files():
      """Return the paths of the strings source files."""
      return itertools.chain(
          glob.iglob("strings*.json"),
          glob.iglob("*{}strings*.json".format(os.sep)),
      )
  
  
  def get_component_platform(path):
      """Get the component and platform name from the path."""
      directory, filename = os.path.split(path)
      match = FILENAME_FORMAT.search(filename)
      suffix = match.group('suffix') if match else None
      if directory:
          return directory, suffix
      else:
          return suffix, None
  
  
  def get_translation_dict(translations, component, platform):
      """Return the dict to hold component translations."""
      if not component:
          return translations['component']
  
      if component not in translations['component']:
          translations['component'][component] = {}
  
      if not platform:
          return translations['component'][component]
  
      if 'platform' not in translations['component'][component]:
          translations['component'][component]['platform'] = {}
  
      if platform not in translations['component'][component]['platform']:
          translations['component'][component]['platform'][platform] = {}
  
      return translations['component'][component]['platform'][platform]
  
  
  def main():
      """Main section of the script."""
      if not os.path.isfile("requirements_all.txt"):
          print("Run this from HA root dir")
          return
  
      root = os.getcwd()
      os.chdir(os.path.join("homeassistant", "components"))
  
      translations = {
          'component': {}
      }
  
      paths = find_strings_files()
      for path in paths:
          component, platform = get_component_platform(path)
          parent = get_translation_dict(translations, component, platform)
          strings = load_json(path)
          parent.update(strings)
  
      os.chdir(root)
  
      os.makedirs("build", exist_ok=True)
  
      save_json(
          os.path.join("build", "translations-upload.json"), translations)
  
  
  if __name__ == '__main__':
      main()
  
subject: Fix bug in translations upload script (#15922)