In original APL, there was only arrays, and inside each cell in an array you could put scalars. A scalar was simply a number or a character. A string is a single-dimensional array of characters, which is quite logical.
Now, with this design, how do you manage a collection of strings? Turns out you can't, so what old software used to do was so have a two-dimensional array of characters. This works reasonably well, except that this means that all strings have to be the same length. You can work with this, but can be very annoying.
What APL2 introduced was the idea that you can not only put scalars inside an array, but also other arrays. This is of course how pretty much every other programming language works, but at the time (as far as I know, this is way before my time) this was seen as very controversial since it made the language less clean, or "elegant".
To go into some details, you can consider a scalar as an array of dimension zero:
⍴⍴5
0
(⍴⍴ returns the dimension of the argument to the right[1])
Once you have nested arrays, you can also wrap an array inside a scalar. This allows you to more easily treat arrays as single objects:
s ← 'hello' ⍝ Assign the string "hello" to s
⍴⍴s ⍝ Confirm that s is a one-dimensional array
1
s2 ← ⊂s ⍝ The ⊂ wraps its argument as a scalar, assign the result to s2
⍴⍴s2 ⍝ The result now has 0 dimensions
0
[1] To go really deep into the technical details, it returns the dimensions of the dimensions of the argument. A scalar has no dimensions, do ⍴5 returns an empty array. The second ⍴ returns zero because an empty array has zero elements.