All user data for FoundryVTT. Includes worlds, systems, modules, and any asset in the "foundryuserdata" directory. Does NOT include the FoundryVTT installation itself.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
2.8 KiB

1 year ago
  1. import CONFIG from "./adventure.mjs";
  2. /**
  3. * Define the structure of adventure data fields which require localization.
  4. * @type {Object<string|Array<object>>}
  5. */
  6. const LOCALIZATION_FIELDS = {
  7. name: "",
  8. description: "",
  9. actors: [{
  10. name: "",
  11. "token.name": ""
  12. }],
  13. folders: [{
  14. name: ""
  15. }],
  16. items: [{
  17. name: "",
  18. "system.description.value": ""
  19. }],
  20. journal: [{
  21. name: ""
  22. }],
  23. macros: [{
  24. name: ""
  25. }],
  26. playlists: [{
  27. name: "",
  28. description: "",
  29. sounds: [{
  30. name: "",
  31. description: ""
  32. }]
  33. }],
  34. scenes: [{
  35. name: "",
  36. navName: "",
  37. notes: [{
  38. text: ""
  39. }],
  40. tokens: [{
  41. name: ""
  42. }]
  43. }]
  44. }
  45. /**
  46. * Extract the values of all localization fields from the provided adventure data
  47. * @returns {Array<object>} The localization schema
  48. */
  49. export async function extractLocalization() {
  50. const pack = game.packs.get(`${CONFIG.moduleId}.${CONFIG.packName}`);
  51. await pack.getDocuments();
  52. for ( const adventure of pack.contents ) {
  53. const adventureConfig = CONFIG.adventure;
  54. const path = `modules/${CONFIG.moduleId}/lang/en/${adventureConfig.slug}`;
  55. await FilePicker.createDirectory("data", path).catch(err => {});
  56. // Extract localization fields
  57. const i18n = _extractLocalizedFields(adventure.toObject());
  58. const lf = _createFile(JSON.stringify(i18n, null, 2), `${adventureConfig.slug}.json`)
  59. await FilePicker.upload("data", path, lf, {}, {notify: false});
  60. // Extract HTML
  61. for ( const entry of adventure.data.journal ) {
  62. if ( !entry.content.trim() ) continue;
  63. const hf = _createFile(entry.content, `${entry._id}-${entry.name.slugify({strict: true})}.html`, "text/html");
  64. await FilePicker.upload("data", path, hf, {}, {notify: false});
  65. }
  66. }
  67. }
  68. /**
  69. * Extract the values of all localization fields from a single document.
  70. * @param {object} documentData
  71. * @param {Object<string|Array<object>>} fields
  72. * @returns {Object<string|Array<object>>}
  73. */
  74. function _extractLocalizedFields(documentData, fields=LOCALIZATION_FIELDS) {
  75. const mapping = {};
  76. for ( const [key, value] of Object.entries(fields) ) {
  77. if ( value instanceof Array ) {
  78. const collection = documentData[key];
  79. const entries = collection.reduce((arr, d) => {
  80. const inner = _extractLocalizedFields(d, value[0]);
  81. if ( inner ) arr.push(inner);
  82. return arr;
  83. }, []);
  84. if ( entries.length > 0 ) mapping[key] = entries;
  85. }
  86. else if ( documentData[key] ) mapping[key] = documentData[key];
  87. }
  88. if ( foundry.utils.isObjectEmpty(mapping) ) return null;
  89. mapping._id = documentData._id;
  90. return mapping;
  91. }
  92. /**
  93. * Create a File object which can be uploaded.
  94. * @returns {File}
  95. * @private
  96. */
  97. function _createFile(content, fileName, dataType) {
  98. const blob = new Blob([content], {type: dataType});
  99. return new File([blob], fileName, {type: dataType});
  100. }