code: private static String[] combineLists(String[][] input,
        String[] output, int r, Language lang) {
      List<String> outputList = new ArrayList<>();
      if (r == input.length) {
        StringBuilder sb = new StringBuilder();
        for (int k = 0; k < output.length; k++) {
          sb.append(output[k]);
          if (k < output.length - 1) {
            sb.append(StringTools.addSpace(output[k + 1], lang));
          }
        }
        outputList.add(sb.toString());
      } else {
        for (int c = 0; c < input[r].length; c++) {
          output[r] = input[r][c];
          String[] sList = combineLists(input, output, r + 1, lang);
          outputList.addAll(Arrays.asList(sList));
        }
      }
      return outputList.toArray(new String[0]);
    }
docs: Creates a Cartesian product of the arrays stored in the input array.
  @param input Array of string arrays to combine.
  @param output Work array of strings.
  @param r Starting parameter (use 0 to get all combinations).
  @param lang Text language for adding spaces in some languages.
  @return Combined array of String.