i18n.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. 'use strict'
  2. // Implementation of chrome.i18n.getMessage
  3. // https://developer.chrome.com/extensions/i18n#method-getMessage
  4. //
  5. // Does not implement predefined messages:
  6. // https://developer.chrome.com/extensions/i18n#overview-predefined
  7. const ipcRenderer = require('@electron/internal/renderer/ipc-renderer-internal')
  8. const fs = require('fs')
  9. const path = require('path')
  10. let metadata
  11. const getExtensionMetadata = (extensionId) => {
  12. if (!metadata) {
  13. metadata = ipcRenderer.sendSync('CHROME_I18N_MANIFEST', extensionId)
  14. }
  15. return metadata
  16. }
  17. const getMessagesPath = (extensionId, language) => {
  18. const metadata = getExtensionMetadata(extensionId)
  19. const localesDirectory = path.join(metadata.srcDirectory, '_locales')
  20. try {
  21. const filename = path.join(localesDirectory, language, 'messages.json')
  22. fs.accessSync(filename, fs.constants.R_OK)
  23. return filename
  24. } catch (err) {
  25. const defaultLocale = metadata.default_locale || 'en'
  26. return path.join(localesDirectory, defaultLocale, 'messages.json')
  27. }
  28. }
  29. const getMessages = (extensionId, language) => {
  30. try {
  31. const messagesPath = getMessagesPath(extensionId, language)
  32. return JSON.parse(fs.readFileSync(messagesPath)) || {}
  33. } catch (error) {
  34. return {}
  35. }
  36. }
  37. const getLanguage = () => {
  38. return navigator.language.replace(/-.*$/, '').toLowerCase()
  39. }
  40. const replaceNumberedSubstitutions = (message, substitutions) => {
  41. return message.replace(/\$(\d+)/, (_, number) => {
  42. const index = parseInt(number, 10) - 1
  43. return substitutions[index] || ''
  44. })
  45. }
  46. const replacePlaceholders = (message, placeholders, substitutions) => {
  47. if (typeof substitutions === 'string') {
  48. substitutions = [substitutions]
  49. }
  50. if (!Array.isArray(substitutions)) {
  51. substitutions = []
  52. }
  53. if (placeholders) {
  54. Object.keys(placeholders).forEach((name) => {
  55. let { content } = placeholders[name]
  56. content = replaceNumberedSubstitutions(content, substitutions)
  57. message = message.replace(new RegExp(`\\$${name}\\$`, 'gi'), content)
  58. })
  59. }
  60. return replaceNumberedSubstitutions(message, substitutions)
  61. }
  62. const getMessage = (extensionId, messageName, substitutions) => {
  63. const messages = getMessages(extensionId, getLanguage())
  64. if (messages.hasOwnProperty(messageName)) {
  65. const { message, placeholders } = messages[messageName]
  66. return replacePlaceholders(message, placeholders, substitutions)
  67. }
  68. }
  69. exports.setup = (extensionId) => {
  70. return {
  71. getMessage (messageName, substitutions) {
  72. return getMessage(extensionId, messageName, substitutions)
  73. }
  74. }
  75. }