i18n.js 2.5 KB

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