Only support single-digit placeholders in formatString (#33934)
Often placeholders can appear next to an actual digit in the translated string (e.g. <ph name="X">$1>0), which will appear on the front end as "$10". In order to interpret such strings correctly, we should only support single-digit placeholders by default. Support for multi-digit placeholders may be added in the future. In addition, formatString has been modified to write errors to the console instead of throw (which can take down the entire page).
This commit is contained in:
@@ -57,18 +57,24 @@ describe('formatString', () => {
|
||||
}), 'People in NZ say Kiora')
|
||||
})
|
||||
|
||||
it('should fail if a replacement does not exist', () => {
|
||||
assert.throws(() => formatString('$1 in $2nz/$2 say $3', {
|
||||
it('should log an error if a replacement does not exist', () => {
|
||||
const consoleSpy = jest.spyOn(console, 'error').mockImplementation()
|
||||
formatString('$1 in $2nz/$2 say $3', {
|
||||
$1: 'People',
|
||||
$2: (content) => content.toUpperCase(),
|
||||
$3: 'Kiora',
|
||||
$4: 'MISSING!'
|
||||
}))
|
||||
})
|
||||
expect(consoleSpy).toHaveBeenCalled()
|
||||
consoleSpy.mockRestore()
|
||||
})
|
||||
|
||||
it('should fail if a replacement does not exist using an array of replacements', () => {
|
||||
assert.throws(() => formatString('$1 in $2nz/$2 say $3',
|
||||
['People', 'NZ', 'Kiora', 'MISSING!']))
|
||||
it('should log an error if a replacement does not exist using an array of replacements', () => {
|
||||
const consoleSpy = jest.spyOn(console, 'error').mockImplementation()
|
||||
formatString('$1 in $2nz/$2 say $3',
|
||||
['People', 'NZ', 'Kiora', 'MISSING!'])
|
||||
expect(consoleSpy).toHaveBeenCalled()
|
||||
consoleSpy.mockRestore()
|
||||
})
|
||||
|
||||
it('should not fail if a replacement does not exist if noErrorOnMissingReplacement is true', () => {
|
||||
@@ -192,5 +198,12 @@ describe('formatString', () => {
|
||||
$2: (content) => <span>{content}</span>
|
||||
}), <>Hello from <span>me</span>{" to "}{"me"}. <span>bob</span> says hi too</>)
|
||||
})
|
||||
|
||||
it('should only support single-digit placeholders ($1-$9)', () => {
|
||||
// $10 should be treated as $1 followed by literal "0"
|
||||
assert.equal(formatString('Hello $10', {
|
||||
$1: 'world'
|
||||
}), 'Hello world0')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ export function formatString<T extends Replacement>(
|
||||
}
|
||||
|
||||
const stack = [result]
|
||||
const regex = /\/?\$(\d+)/gm
|
||||
const regex = /\/?\$([1-9])/gm
|
||||
|
||||
// Keep track of the keys we've seen, so we can throw an error if a key is
|
||||
// missing.
|
||||
@@ -116,7 +116,7 @@ export function formatString<T extends Replacement>(
|
||||
if (stack.at(-1)!.key === key) {
|
||||
stack.pop()
|
||||
} else {
|
||||
throw new Error(`Mismatched closing tag: ${tag} in message "${text}"`)
|
||||
console.error(`Mismatched closing tag: ${tag} in message "${text}"`)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -155,7 +155,7 @@ export function formatString<T extends Replacement>(
|
||||
// If we should throw an error for missing replacements check to see if they
|
||||
// were all present in our text.
|
||||
if (!options?.noErrorOnMissingReplacement && seen.size < Object.keys(replacements).length) {
|
||||
throw new Error(`Missing replacements (${Object.keys(replacements).filter(key => !seen.has(key)).join(', ')} we not found in ${text})`)
|
||||
console.error(`Missing replacements (${Object.keys(replacements).filter(key => !seen.has(key)).join(', ')} we not found in ${text})`)
|
||||
}
|
||||
|
||||
const formatted = getReplacedContent(result)
|
||||
|
||||
Reference in New Issue
Block a user